back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_updgrp_adv.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 9 461 2.0 %
Date: 2023-02-24 18:37:55 Functions: 2 26 7.7 %

          Line data    Source code
       1             : /**
       2             :  * bgp_updgrp_adv.c: BGP update group advertisement and adjacency
       3             :  *                   maintenance
       4             :  *
       5             :  *
       6             :  * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
       7             :  *
       8             :  * @author Avneesh Sachdev <avneesh@sproute.net>
       9             :  * @author Rajesh Varadarajan <rajesh@sproute.net>
      10             :  * @author Pradosh Mohapatra <pradosh@sproute.net>
      11             :  *
      12             :  * This file is part of GNU Zebra.
      13             :  *
      14             :  * GNU Zebra is free software; you can redistribute it and/or modify it
      15             :  * under the terms of the GNU General Public License as published by the
      16             :  * Free Software Foundation; either version 2, or (at your option) any
      17             :  * later version.
      18             :  *
      19             :  * GNU Zebra is distributed in the hope that it will be useful, but
      20             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      22             :  * General Public License for more details.
      23             :  *
      24             :  * You should have received a copy of the GNU General Public License along
      25             :  * with this program; see the file COPYING; if not, write to the Free Software
      26             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      27             :  */
      28             : 
      29             : #include <zebra.h>
      30             : 
      31             : #include "command.h"
      32             : #include "memory.h"
      33             : #include "prefix.h"
      34             : #include "hash.h"
      35             : #include "thread.h"
      36             : #include "queue.h"
      37             : #include "routemap.h"
      38             : #include "filter.h"
      39             : 
      40             : #include "bgpd/bgpd.h"
      41             : #include "bgpd/bgp_table.h"
      42             : #include "bgpd/bgp_debug.h"
      43             : #include "bgpd/bgp_route.h"
      44             : #include "bgpd/bgp_advertise.h"
      45             : #include "bgpd/bgp_attr.h"
      46             : #include "bgpd/bgp_aspath.h"
      47             : #include "bgpd/bgp_packet.h"
      48             : #include "bgpd/bgp_fsm.h"
      49             : #include "bgpd/bgp_mplsvpn.h"
      50             : #include "bgpd/bgp_updgrp.h"
      51             : #include "bgpd/bgp_advertise.h"
      52             : #include "bgpd/bgp_addpath.h"
      53             : 
      54             : 
      55             : /********************
      56             :  * PRIVATE FUNCTIONS
      57             :  ********************/
      58           0 : static int bgp_adj_out_compare(const struct bgp_adj_out *o1,
      59             :                                const struct bgp_adj_out *o2)
      60             : {
      61           0 :         if (o1->subgroup < o2->subgroup)
      62             :                 return -1;
      63             : 
      64           0 :         if (o1->subgroup > o2->subgroup)
      65             :                 return 1;
      66             : 
      67           0 :         if (o1->addpath_tx_id < o2->addpath_tx_id)
      68             :                 return -1;
      69             : 
      70           0 :         if (o1->addpath_tx_id > o2->addpath_tx_id)
      71             :                 return 1;
      72             : 
      73             :         return 0;
      74             : }
      75           0 : RB_GENERATE(bgp_adj_out_rb, bgp_adj_out, adj_entry, bgp_adj_out_compare);
      76             : 
      77           0 : static inline struct bgp_adj_out *adj_lookup(struct bgp_dest *dest,
      78             :                                              struct update_subgroup *subgrp,
      79             :                                              uint32_t addpath_tx_id)
      80             : {
      81           0 :         struct bgp_adj_out lookup;
      82             : 
      83           0 :         if (!dest || !subgrp)
      84             :                 return NULL;
      85             : 
      86             :         /* update-groups that do not support addpath will pass 0 for
      87             :          * addpath_tx_id. */
      88           0 :         lookup.subgroup = subgrp;
      89           0 :         lookup.addpath_tx_id = addpath_tx_id;
      90             : 
      91           0 :         return RB_FIND(bgp_adj_out_rb, &dest->adj_out, &lookup);
      92             : }
      93             : 
      94           0 : static void adj_free(struct bgp_adj_out *adj)
      95             : {
      96           0 :         TAILQ_REMOVE(&(adj->subgroup->adjq), adj, subgrp_adj_train);
      97           0 :         SUBGRP_DECR_STAT(adj->subgroup, adj_count);
      98             : 
      99           0 :         RB_REMOVE(bgp_adj_out_rb, &adj->dest->adj_out, adj);
     100           0 :         bgp_dest_unlock_node(adj->dest);
     101             : 
     102           0 :         XFREE(MTYPE_BGP_ADJ_OUT, adj);
     103           0 : }
     104             : 
     105           0 : static void subgrp_withdraw_stale_addpath(struct updwalk_context *ctx,
     106             :                                           struct update_subgroup *subgrp)
     107             : {
     108           0 :         struct bgp_adj_out *adj, *adj_next;
     109           0 :         uint32_t id;
     110           0 :         struct bgp_path_info *pi;
     111           0 :         afi_t afi = SUBGRP_AFI(subgrp);
     112           0 :         safi_t safi = SUBGRP_SAFI(subgrp);
     113           0 :         struct peer *peer = SUBGRP_PEER(subgrp);
     114             : 
     115             :         /* Look through all of the paths we have advertised for this rn and send
     116             :          * a withdraw for the ones that are no longer present */
     117           0 :         RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->dest->adj_out, adj_next) {
     118           0 :                 if (adj->subgroup != subgrp)
     119           0 :                         continue;
     120             : 
     121           0 :                 for (pi = bgp_dest_get_bgp_path_info(ctx->dest); pi;
     122           0 :                      pi = pi->next) {
     123           0 :                         id = bgp_addpath_id_for_peer(peer, afi, safi,
     124             :                                                      &pi->tx_addpath);
     125             : 
     126           0 :                         if (id == adj->addpath_tx_id) {
     127             :                                 break;
     128             :                         }
     129             :                 }
     130             : 
     131           0 :                 if (!pi) {
     132           0 :                         subgroup_process_announce_selected(
     133             :                                 subgrp, NULL, ctx->dest, adj->addpath_tx_id);
     134             :                 }
     135             :         }
     136           0 : }
     137             : 
     138           0 : static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
     139             : {
     140           0 :         struct updwalk_context *ctx = arg;
     141           0 :         struct update_subgroup *subgrp;
     142           0 :         struct bgp_path_info *pi;
     143           0 :         afi_t afi;
     144           0 :         safi_t safi;
     145           0 :         struct peer *peer;
     146           0 :         struct bgp_adj_out *adj, *adj_next;
     147           0 :         bool addpath_capable;
     148             : 
     149           0 :         afi = UPDGRP_AFI(updgrp);
     150           0 :         safi = UPDGRP_SAFI(updgrp);
     151           0 :         peer = UPDGRP_PEER(updgrp);
     152           0 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
     153             : 
     154           0 :         if (BGP_DEBUG(update, UPDATE_OUT))
     155           0 :                 zlog_debug("%s: afi=%s, safi=%s, p=%pRN", __func__,
     156             :                            afi2str(afi), safi2str(safi),
     157             :                            bgp_dest_to_rnode(ctx->dest));
     158             : 
     159           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     160             : 
     161             :                 /*
     162             :                  * Skip the subgroups that have coalesce timer running. We will
     163             :                  * walk the entire prefix table for those subgroups when the
     164             :                  * coalesce timer fires.
     165             :                  */
     166           0 :                 if (!subgrp->t_coalesce) {
     167             : 
     168             :                         /* An update-group that uses addpath */
     169           0 :                         if (addpath_capable) {
     170           0 :                                 subgrp_withdraw_stale_addpath(ctx, subgrp);
     171             : 
     172           0 :                                 for (pi = bgp_dest_get_bgp_path_info(ctx->dest);
     173           0 :                                      pi; pi = pi->next) {
     174             :                                         /* Skip the bestpath for now */
     175           0 :                                         if (pi == ctx->pi)
     176           0 :                                                 continue;
     177             : 
     178           0 :                                         subgroup_process_announce_selected(
     179             :                                                 subgrp, pi, ctx->dest,
     180             :                                                 bgp_addpath_id_for_peer(
     181             :                                                         peer, afi, safi,
     182             :                                                         &pi->tx_addpath));
     183             :                                 }
     184             : 
     185             :                                 /* Process the bestpath last so the "show [ip]
     186             :                                  * bgp neighbor x.x.x.x advertised"
     187             :                                  * output shows the attributes from the bestpath
     188             :                                  */
     189           0 :                                 if (ctx->pi)
     190           0 :                                         subgroup_process_announce_selected(
     191             :                                                 subgrp, ctx->pi, ctx->dest,
     192             :                                                 bgp_addpath_id_for_peer(
     193             :                                                         peer, afi, safi,
     194             :                                                         &ctx->pi->tx_addpath));
     195             :                         }
     196             :                         /* An update-group that does not use addpath */
     197             :                         else {
     198           0 :                                 if (ctx->pi) {
     199           0 :                                         subgroup_process_announce_selected(
     200             :                                                 subgrp, ctx->pi, ctx->dest,
     201             :                                                 bgp_addpath_id_for_peer(
     202             :                                                         peer, afi, safi,
     203             :                                                         &ctx->pi->tx_addpath));
     204             :                                 } else {
     205             :                                         /* Find the addpath_tx_id of the path we
     206             :                                          * had advertised and
     207             :                                          * send a withdraw */
     208           0 :                                         RB_FOREACH_SAFE (adj, bgp_adj_out_rb,
     209             :                                                          &ctx->dest->adj_out,
     210             :                                                          adj_next) {
     211           0 :                                                 if (adj->subgroup == subgrp) {
     212           0 :                                                         subgroup_process_announce_selected(
     213             :                                                                 subgrp, NULL,
     214             :                                                                 ctx->dest,
     215             :                                                                 adj->addpath_tx_id);
     216             :                                                 }
     217             :                                         }
     218             :                                 }
     219             :                         }
     220             :                 }
     221             : 
     222             :                 /* Notify BGP Conditional advertisement */
     223           0 :                 bgp_notify_conditional_adv_scanner(subgrp);
     224             :         }
     225             : 
     226           0 :         return UPDWALK_CONTINUE;
     227             : }
     228             : 
     229           0 : static void subgrp_show_adjq_vty(struct update_subgroup *subgrp,
     230             :                                  struct vty *vty, uint8_t flags)
     231             : {
     232           0 :         struct bgp_table *table;
     233           0 :         struct bgp_adj_out *adj;
     234           0 :         unsigned long output_count;
     235           0 :         struct bgp_dest *dest;
     236           0 :         int header1 = 1;
     237           0 :         struct bgp *bgp;
     238           0 :         int header2 = 1;
     239             : 
     240           0 :         bgp = SUBGRP_INST(subgrp);
     241           0 :         if (!bgp)
     242             :                 return;
     243             : 
     244           0 :         table = bgp->rib[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)];
     245             : 
     246           0 :         output_count = 0;
     247             : 
     248           0 :         for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
     249           0 :                 const struct prefix *dest_p = bgp_dest_get_prefix(dest);
     250             : 
     251           0 :                 RB_FOREACH (adj, bgp_adj_out_rb, &dest->adj_out) {
     252           0 :                         if (adj->subgroup != subgrp)
     253           0 :                                 continue;
     254             : 
     255           0 :                         if (header1) {
     256           0 :                                 vty_out(vty,
     257             :                                         "BGP table version is %" PRIu64
     258             :                                         ", local router ID is %pI4\n",
     259             :                                         table->version, &bgp->router_id);
     260           0 :                                 vty_out(vty, BGP_SHOW_SCODE_HEADER);
     261           0 :                                 vty_out(vty, BGP_SHOW_OCODE_HEADER);
     262           0 :                                 header1 = 0;
     263             :                         }
     264           0 :                         if (header2) {
     265           0 :                                 vty_out(vty, BGP_SHOW_HEADER);
     266           0 :                                 header2 = 0;
     267             :                         }
     268           0 :                         if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv &&
     269           0 :                             adj->adv->baa) {
     270           0 :                                 route_vty_out_tmp(
     271             :                                         vty, dest, dest_p, adj->adv->baa->attr,
     272           0 :                                         SUBGRP_SAFI(subgrp), 0, NULL, false);
     273           0 :                                 output_count++;
     274             :                         }
     275           0 :                         if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr) {
     276           0 :                                 route_vty_out_tmp(vty, dest, dest_p, adj->attr,
     277           0 :                                                   SUBGRP_SAFI(subgrp), 0, NULL,
     278             :                                                   false);
     279           0 :                                 output_count++;
     280             :                         }
     281             :                 }
     282             :         }
     283           0 :         if (output_count != 0)
     284           0 :                 vty_out(vty, "\nTotal number of prefixes %ld\n", output_count);
     285             : }
     286             : 
     287           0 : static int updgrp_show_adj_walkcb(struct update_group *updgrp, void *arg)
     288             : {
     289           0 :         struct updwalk_context *ctx = arg;
     290           0 :         struct update_subgroup *subgrp;
     291           0 :         struct vty *vty;
     292             : 
     293           0 :         vty = ctx->vty;
     294           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     295           0 :                 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
     296           0 :                         continue;
     297           0 :                 vty_out(vty, "update group %" PRIu64 ", subgroup %" PRIu64 "\n",
     298             :                         updgrp->id, subgrp->id);
     299           0 :                 subgrp_show_adjq_vty(subgrp, vty, ctx->flags);
     300             :         }
     301           0 :         return UPDWALK_CONTINUE;
     302             : }
     303             : 
     304           0 : static void updgrp_show_adj(struct bgp *bgp, afi_t afi, safi_t safi,
     305             :                             struct vty *vty, uint64_t id, uint8_t flags)
     306             : {
     307           0 :         struct updwalk_context ctx;
     308           0 :         memset(&ctx, 0, sizeof(ctx));
     309           0 :         ctx.vty = vty;
     310           0 :         ctx.subgrp_id = id;
     311           0 :         ctx.flags = flags;
     312             : 
     313           0 :         update_group_af_walk(bgp, afi, safi, updgrp_show_adj_walkcb, &ctx);
     314           0 : }
     315             : 
     316           0 : static void subgroup_coalesce_timer(struct thread *thread)
     317             : {
     318           0 :         struct update_subgroup *subgrp;
     319           0 :         struct bgp *bgp;
     320             : 
     321           0 :         subgrp = THREAD_ARG(thread);
     322           0 :         if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
     323           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64" announcing routes upon coalesce timer expiry(%u ms)",
     324             :                            (SUBGRP_UPDGRP(subgrp))->id, subgrp->id,
     325             :                            subgrp->v_coalesce);
     326           0 :         subgrp->t_coalesce = NULL;
     327           0 :         subgrp->v_coalesce = 0;
     328           0 :         bgp = SUBGRP_INST(subgrp);
     329           0 :         subgroup_announce_route(subgrp);
     330             : 
     331             : 
     332             :         /* While the announce_route() may kick off the route advertisement timer
     333             :          * for
     334             :          * the members of the subgroup, we'd like to send the initial updates
     335             :          * much
     336             :          * faster (i.e., without enforcing MRAI). Also, if there were no routes
     337             :          * to
     338             :          * announce, this is the method currently employed to trigger the EOR.
     339             :          */
     340           0 :         if (!bgp_update_delay_active(SUBGRP_INST(subgrp)) &&
     341           0 :             !(BGP_SUPPRESS_FIB_ENABLED(bgp))) {
     342           0 :                 struct peer_af *paf;
     343           0 :                 struct peer *peer;
     344             : 
     345           0 :                 SUBGRP_FOREACH_PEER (subgrp, paf) {
     346           0 :                         peer = PAF_PEER(paf);
     347           0 :                         THREAD_OFF(peer->t_routeadv);
     348           0 :                         BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
     349             :                 }
     350             :         }
     351           0 : }
     352             : 
     353           0 : static int update_group_announce_walkcb(struct update_group *updgrp, void *arg)
     354             : {
     355           0 :         struct update_subgroup *subgrp;
     356             : 
     357           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     358             :                 /* Avoid supressing duplicate routes later
     359             :                  * when processing in subgroup_announce_table().
     360             :                  */
     361           0 :                 SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
     362             : 
     363           0 :                 subgroup_announce_all(subgrp);
     364             :         }
     365             : 
     366           0 :         return UPDWALK_CONTINUE;
     367             : }
     368             : 
     369           0 : static int update_group_announce_rrc_walkcb(struct update_group *updgrp,
     370             :                                             void *arg)
     371             : {
     372           0 :         struct update_subgroup *subgrp;
     373           0 :         afi_t afi;
     374           0 :         safi_t safi;
     375           0 :         struct peer *peer;
     376             : 
     377           0 :         afi = UPDGRP_AFI(updgrp);
     378           0 :         safi = UPDGRP_SAFI(updgrp);
     379           0 :         peer = UPDGRP_PEER(updgrp);
     380             : 
     381             :         /* Only announce if this is a group of route-reflector-clients */
     382           0 :         if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) {
     383           0 :                 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     384           0 :                         subgroup_announce_all(subgrp);
     385             :                 }
     386             :         }
     387             : 
     388           0 :         return UPDWALK_CONTINUE;
     389             : }
     390             : 
     391             : /********************
     392             :  * PUBLIC FUNCTIONS
     393             :  ********************/
     394             : 
     395             : /**
     396             :  * Allocate an adj-out object. Do proper initialization of its fields,
     397             :  * primarily its association with the subgroup and the prefix.
     398             :  */
     399           0 : struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp,
     400             :                                       struct bgp_dest *dest,
     401             :                                       uint32_t addpath_tx_id)
     402             : {
     403           0 :         struct bgp_adj_out *adj;
     404             : 
     405           0 :         adj = XCALLOC(MTYPE_BGP_ADJ_OUT, sizeof(struct bgp_adj_out));
     406           0 :         adj->subgroup = subgrp;
     407           0 :         adj->addpath_tx_id = addpath_tx_id;
     408             : 
     409           0 :         RB_INSERT(bgp_adj_out_rb, &dest->adj_out, adj);
     410           0 :         bgp_dest_lock_node(dest);
     411           0 :         adj->dest = dest;
     412             : 
     413           0 :         TAILQ_INSERT_TAIL(&(subgrp->adjq), adj, subgrp_adj_train);
     414           0 :         SUBGRP_INCR_STAT(subgrp, adj_count);
     415           0 :         return adj;
     416             : }
     417             : 
     418             : 
     419             : struct bgp_advertise *
     420           0 : bgp_advertise_clean_subgroup(struct update_subgroup *subgrp,
     421             :                              struct bgp_adj_out *adj)
     422             : {
     423           0 :         struct bgp_advertise *adv;
     424           0 :         struct bgp_advertise_attr *baa;
     425           0 :         struct bgp_advertise *next;
     426           0 :         struct bgp_adv_fifo_head *fhead;
     427             : 
     428           0 :         adv = adj->adv;
     429           0 :         baa = adv->baa;
     430           0 :         next = NULL;
     431             : 
     432           0 :         if (baa) {
     433           0 :                 fhead = &subgrp->sync->update;
     434             : 
     435             :                 /* Unlink myself from advertise attribute FIFO.  */
     436           0 :                 bgp_advertise_delete(baa, adv);
     437             : 
     438             :                 /* Fetch next advertise candidate. */
     439           0 :                 next = baa->adv;
     440             : 
     441             :                 /* Unintern BGP advertise attribute.  */
     442           0 :                 bgp_advertise_attr_unintern(subgrp->hash, baa);
     443             :         } else
     444           0 :                 fhead = &subgrp->sync->withdraw;
     445             : 
     446             : 
     447             :         /* Unlink myself from advertisement FIFO.  */
     448           0 :         bgp_adv_fifo_del(fhead, adv);
     449             : 
     450             :         /* Free memory.  */
     451           0 :         bgp_advertise_free(adj->adv);
     452           0 :         adj->adv = NULL;
     453             : 
     454           0 :         return next;
     455             : }
     456             : 
     457           0 : void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
     458             :                               struct update_subgroup *subgrp, struct attr *attr,
     459             :                               struct bgp_path_info *path)
     460             : {
     461           0 :         struct bgp_adj_out *adj = NULL;
     462           0 :         struct bgp_advertise *adv;
     463           0 :         struct peer *peer;
     464           0 :         afi_t afi;
     465           0 :         safi_t safi;
     466           0 :         struct peer *adv_peer;
     467           0 :         struct peer_af *paf;
     468           0 :         struct bgp *bgp;
     469           0 :         uint32_t attr_hash = attrhash_key_make(attr);
     470             : 
     471           0 :         peer = SUBGRP_PEER(subgrp);
     472           0 :         afi = SUBGRP_AFI(subgrp);
     473           0 :         safi = SUBGRP_SAFI(subgrp);
     474           0 :         bgp = SUBGRP_INST(subgrp);
     475             : 
     476           0 :         if (DISABLE_BGP_ANNOUNCE)
     477             :                 return;
     478             : 
     479             :         /* Look for adjacency information. */
     480           0 :         adj = adj_lookup(
     481             :                 dest, subgrp,
     482             :                 bgp_addpath_id_for_peer(peer, afi, safi, &path->tx_addpath));
     483             : 
     484           0 :         if (adj) {
     485           0 :                 if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING))
     486           0 :                         subgrp->pscount++;
     487             :         } else {
     488           0 :                 adj = bgp_adj_out_alloc(
     489             :                         subgrp, dest,
     490             :                         bgp_addpath_id_for_peer(peer, afi, safi,
     491             :                                                 &path->tx_addpath));
     492           0 :                 if (!adj)
     493             :                         return;
     494             : 
     495           0 :                 subgrp->pscount++;
     496             :         }
     497             : 
     498             :         /* Check if we are sending the same route. This is needed to
     499             :          * avoid duplicate UPDATES. For instance, filtering communities
     500             :          * at egress, neighbors will see duplicate UPDATES despite
     501             :          * the route wasn't changed actually.
     502             :          * Do not suppress BGP UPDATES for route-refresh.
     503             :          */
     504           0 :         if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES)
     505           0 :             && !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES)
     506           0 :             && adj->attr_hash == attr_hash) {
     507           0 :                 if (BGP_DEBUG(update, UPDATE_OUT)) {
     508           0 :                         char attr_str[BUFSIZ] = {0};
     509             : 
     510           0 :                         bgp_dump_attr(attr, attr_str, sizeof(attr_str));
     511             : 
     512           0 :                         zlog_debug("%s suppress UPDATE w/ attr: %s", peer->host,
     513             :                                    attr_str);
     514             :                 }
     515           0 :                 return;
     516             :         }
     517             : 
     518           0 :         if (adj->adv)
     519           0 :                 bgp_advertise_clean_subgroup(subgrp, adj);
     520           0 :         adj->adv = bgp_advertise_new();
     521             : 
     522           0 :         adv = adj->adv;
     523           0 :         adv->dest = dest;
     524           0 :         assert(adv->pathi == NULL);
     525             :         /* bgp_path_info adj_out reference */
     526           0 :         adv->pathi = bgp_path_info_lock(path);
     527             : 
     528           0 :         adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr);
     529           0 :         adv->adj = adj;
     530           0 :         adj->attr_hash = attr_hash;
     531             : 
     532             :         /* Add new advertisement to advertisement attribute list. */
     533           0 :         bgp_advertise_add(adv->baa, adv);
     534             : 
     535             :         /*
     536             :          * If the update adv list is empty, trigger the member peers'
     537             :          * mrai timers so the socket writes can happen.
     538             :          */
     539           0 :         if (!bgp_adv_fifo_count(&subgrp->sync->update)) {
     540           0 :                 SUBGRP_FOREACH_PEER (subgrp, paf) {
     541             :                         /* If there are no routes in the withdraw list, set
     542             :                          * the flag PEER_STATUS_ADV_DELAY which will allow
     543             :                          * more routes to be sent in the update message
     544             :                          */
     545           0 :                         if (BGP_SUPPRESS_FIB_ENABLED(bgp)) {
     546           0 :                                 adv_peer = PAF_PEER(paf);
     547           0 :                                 if (!bgp_adv_fifo_count(
     548           0 :                                                 &subgrp->sync->withdraw))
     549           0 :                                         SET_FLAG(adv_peer->thread_flags,
     550             :                                                  PEER_THREAD_SUBGRP_ADV_DELAY);
     551             :                                 else
     552           0 :                                         UNSET_FLAG(adv_peer->thread_flags,
     553             :                                                 PEER_THREAD_SUBGRP_ADV_DELAY);
     554             :                         }
     555           0 :                         bgp_adjust_routeadv(PAF_PEER(paf));
     556             :                 }
     557             :         }
     558             : 
     559           0 :         bgp_adv_fifo_add_tail(&subgrp->sync->update, adv);
     560             : 
     561           0 :         subgrp->version = MAX(subgrp->version, dest->version);
     562             : }
     563             : 
     564             : /* The only time 'withdraw' will be false is if we are sending
     565             :  * the "neighbor x.x.x.x default-originate" default and need to clear
     566             :  * bgp_adj_out for the 0.0.0.0/0 route in the BGP table.
     567             :  */
     568           0 : void bgp_adj_out_unset_subgroup(struct bgp_dest *dest,
     569             :                                 struct update_subgroup *subgrp, char withdraw,
     570             :                                 uint32_t addpath_tx_id)
     571             : {
     572           0 :         struct bgp_adj_out *adj;
     573           0 :         struct bgp_advertise *adv;
     574           0 :         bool trigger_write;
     575             : 
     576           0 :         if (DISABLE_BGP_ANNOUNCE)
     577             :                 return;
     578             : 
     579             :         /* Lookup existing adjacency */
     580           0 :         adj = adj_lookup(dest, subgrp, addpath_tx_id);
     581           0 :         if (adj != NULL) {
     582             :                 /* Clean up previous advertisement.  */
     583           0 :                 if (adj->adv)
     584           0 :                         bgp_advertise_clean_subgroup(subgrp, adj);
     585             : 
     586             :                 /* If default originate is enabled and the route is default
     587             :                  * route, do not send withdraw. This will prevent deletion of
     588             :                  * the default route at the peer.
     589             :                  */
     590           0 :                 if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)
     591           0 :                     && is_default_prefix(bgp_dest_get_prefix(dest)))
     592             :                         return;
     593             : 
     594           0 :                 if (adj->attr && withdraw) {
     595             :                         /* We need advertisement structure.  */
     596           0 :                         adj->adv = bgp_advertise_new();
     597           0 :                         adv = adj->adv;
     598           0 :                         adv->dest = dest;
     599           0 :                         adv->adj = adj;
     600             : 
     601             :                         /* Note if we need to trigger a packet write */
     602           0 :                         trigger_write =
     603           0 :                                 !bgp_adv_fifo_count(&subgrp->sync->withdraw);
     604             : 
     605             :                         /* Add to synchronization entry for withdraw
     606             :                          * announcement.  */
     607           0 :                         bgp_adv_fifo_add_tail(&subgrp->sync->withdraw, adv);
     608             : 
     609           0 :                         if (trigger_write)
     610           0 :                                 subgroup_trigger_write(subgrp);
     611             :                 } else {
     612             :                         /* Free allocated information.  */
     613           0 :                         adj_free(adj);
     614             :                 }
     615           0 :                 if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING))
     616           0 :                         subgrp->pscount--;
     617             :         }
     618             : 
     619           0 :         subgrp->version = MAX(subgrp->version, dest->version);
     620             : }
     621             : 
     622           0 : void bgp_adj_out_remove_subgroup(struct bgp_dest *dest, struct bgp_adj_out *adj,
     623             :                                  struct update_subgroup *subgrp)
     624             : {
     625           0 :         if (adj->attr)
     626           0 :                 bgp_attr_unintern(&adj->attr);
     627             : 
     628           0 :         if (adj->adv)
     629           0 :                 bgp_advertise_clean_subgroup(subgrp, adj);
     630             : 
     631           0 :         adj_free(adj);
     632           0 : }
     633             : 
     634             : /*
     635             :  * Go through all the routes and clean up the adj/adv structures corresponding
     636             :  * to the subgroup.
     637             :  */
     638           1 : void subgroup_clear_table(struct update_subgroup *subgrp)
     639             : {
     640           1 :         struct bgp_adj_out *aout, *taout;
     641             : 
     642           1 :         SUBGRP_FOREACH_ADJ_SAFE (subgrp, aout, taout)
     643           0 :                 bgp_adj_out_remove_subgroup(aout->dest, aout, subgrp);
     644           1 : }
     645             : 
     646             : /*
     647             :  * subgroup_announce_table
     648             :  */
     649           0 : void subgroup_announce_table(struct update_subgroup *subgrp,
     650             :                              struct bgp_table *table)
     651             : {
     652           0 :         struct bgp_dest *dest;
     653           0 :         struct bgp_path_info *ri;
     654           0 :         struct attr attr;
     655           0 :         struct peer *peer;
     656           0 :         afi_t afi;
     657           0 :         safi_t safi;
     658           0 :         safi_t safi_rib;
     659           0 :         bool addpath_capable;
     660           0 :         struct bgp *bgp;
     661           0 :         bool advertise;
     662             : 
     663           0 :         peer = SUBGRP_PEER(subgrp);
     664           0 :         afi = SUBGRP_AFI(subgrp);
     665           0 :         safi = SUBGRP_SAFI(subgrp);
     666           0 :         bgp = SUBGRP_INST(subgrp);
     667           0 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
     668             : 
     669           0 :         if (safi == SAFI_LABELED_UNICAST)
     670             :                 safi_rib = SAFI_UNICAST;
     671             :         else
     672           0 :                 safi_rib = safi;
     673             : 
     674           0 :         if (!table)
     675           0 :                 table = peer->bgp->rib[afi][safi_rib];
     676             : 
     677           0 :         if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN
     678           0 :             && CHECK_FLAG(peer->af_flags[afi][safi],
     679             :                           PEER_FLAG_DEFAULT_ORIGINATE))
     680           0 :                 subgroup_default_originate(subgrp, 0);
     681             : 
     682           0 :         subgrp->pscount = 0;
     683           0 :         SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
     684             : 
     685           0 :         for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
     686           0 :                 const struct prefix *dest_p = bgp_dest_get_prefix(dest);
     687             : 
     688             :                 /* Check if the route can be advertised */
     689           0 :                 advertise = bgp_check_advertise(bgp, dest);
     690             : 
     691           0 :                 for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next) {
     692             : 
     693           0 :                         if (!bgp_check_selected(ri, peer, addpath_capable, afi,
     694             :                                                 safi_rib))
     695           0 :                                 continue;
     696             : 
     697           0 :                         if (subgroup_announce_check(dest, ri, subgrp, dest_p,
     698             :                                                     &attr, NULL)) {
     699             :                                 /* Check if route can be advertised */
     700           0 :                                 if (advertise) {
     701           0 :                                         if (!bgp_check_withdrawal(bgp, dest))
     702           0 :                                                 bgp_adj_out_set_subgroup(
     703             :                                                         dest, subgrp, &attr,
     704             :                                                         ri);
     705             :                                         else
     706           0 :                                                 bgp_adj_out_unset_subgroup(
     707             :                                                         dest, subgrp, 1,
     708             :                                                         bgp_addpath_id_for_peer(
     709             :                                                                 peer, afi,
     710             :                                                                 safi_rib,
     711             :                                                                 &ri->tx_addpath));
     712             :                                 }
     713             :                         } else {
     714             :                                 /* If default originate is enabled for
     715             :                                  * the peer, do not send explicit
     716             :                                  * withdraw. This will prevent deletion
     717             :                                  * of default route advertised through
     718             :                                  * default originate
     719             :                                  */
     720           0 :                                 if (CHECK_FLAG(peer->af_flags[afi][safi],
     721           0 :                                                PEER_FLAG_DEFAULT_ORIGINATE) &&
     722           0 :                                     is_default_prefix(
     723             :                                             bgp_dest_get_prefix(dest)))
     724             :                                         break;
     725             : 
     726           0 :                                 bgp_adj_out_unset_subgroup(
     727             :                                         dest, subgrp, 1,
     728             :                                         bgp_addpath_id_for_peer(
     729             :                                                 peer, afi, safi_rib,
     730             :                                                 &ri->tx_addpath));
     731             :                         }
     732             :                 }
     733             :         }
     734           0 :         UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
     735             : 
     736             :         /*
     737             :          * We walked through the whole table -- make sure our version number
     738             :          * is consistent with the one on the table. This should allow
     739             :          * subgroups to merge sooner if a peer comes up when the route node
     740             :          * with the largest version is no longer in the table. This also
     741             :          * covers the pathological case where all routes in the table have
     742             :          * now been deleted.
     743             :          */
     744           0 :         subgrp->version = MAX(subgrp->version, table->version);
     745             : 
     746             :         /*
     747             :          * Start a task to merge the subgroup if necessary.
     748             :          */
     749           0 :         update_subgroup_trigger_merge_check(subgrp, 0);
     750           0 : }
     751             : 
     752             : /*
     753             :  * subgroup_announce_route
     754             :  *
     755             :  * Refresh all routes out to a subgroup.
     756             :  */
     757           0 : void subgroup_announce_route(struct update_subgroup *subgrp)
     758             : {
     759           0 :         struct bgp_dest *dest;
     760           0 :         struct bgp_table *table;
     761           0 :         struct peer *onlypeer;
     762             : 
     763           0 :         if (update_subgroup_needs_refresh(subgrp)) {
     764           0 :                 update_subgroup_set_needs_refresh(subgrp, 0);
     765             :         }
     766             : 
     767             :         /*
     768             :          * First update is deferred until ORF or ROUTE-REFRESH is received
     769             :          */
     770           0 :         onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer
     771           0 :                                                  : NULL);
     772           0 :         if (onlypeer && CHECK_FLAG(onlypeer->af_sflags[SUBGRP_AFI(subgrp)]
     773             :                                                       [SUBGRP_SAFI(subgrp)],
     774             :                                    PEER_STATUS_ORF_WAIT_REFRESH))
     775             :                 return;
     776             : 
     777           0 :         if (SUBGRP_SAFI(subgrp) != SAFI_MPLS_VPN
     778             :             && SUBGRP_SAFI(subgrp) != SAFI_ENCAP
     779           0 :             && SUBGRP_SAFI(subgrp) != SAFI_EVPN)
     780           0 :                 subgroup_announce_table(subgrp, NULL);
     781             :         else
     782           0 :                 for (dest = bgp_table_top(update_subgroup_rib(subgrp)); dest;
     783           0 :                      dest = bgp_route_next(dest)) {
     784           0 :                         table = bgp_dest_get_bgp_table_info(dest);
     785           0 :                         if (!table)
     786           0 :                                 continue;
     787           0 :                         subgroup_announce_table(subgrp, table);
     788             :                 }
     789             : }
     790             : 
     791           0 : void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
     792             : {
     793           0 :         struct bgp *bgp;
     794           0 :         struct attr attr;
     795           0 :         struct attr *new_attr = &attr;
     796           0 :         struct prefix p;
     797           0 :         struct peer *from;
     798           0 :         struct bgp_dest *dest;
     799           0 :         struct bgp_path_info *pi;
     800           0 :         struct peer *peer;
     801           0 :         struct bgp_adj_out *adj;
     802           0 :         route_map_result_t ret = RMAP_DENYMATCH;
     803           0 :         route_map_result_t new_ret = RMAP_DENYMATCH;
     804           0 :         afi_t afi;
     805           0 :         safi_t safi;
     806           0 :         safi_t safi_rib;
     807           0 :         int pref = 65536;
     808           0 :         int new_pref = 0;
     809             : 
     810           0 :         if (!subgrp)
     811           0 :                 return;
     812             : 
     813           0 :         peer = SUBGRP_PEER(subgrp);
     814           0 :         afi = SUBGRP_AFI(subgrp);
     815           0 :         safi = SUBGRP_SAFI(subgrp);
     816             : 
     817           0 :         if (!(afi == AFI_IP || afi == AFI_IP6))
     818             :                 return;
     819             : 
     820           0 :         if (safi == SAFI_LABELED_UNICAST)
     821             :                 safi_rib = SAFI_UNICAST;
     822             :         else
     823           0 :                 safi_rib = safi;
     824             : 
     825           0 :         bgp = peer->bgp;
     826           0 :         from = bgp->peer_self;
     827             : 
     828           0 :         bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_IGP);
     829             : 
     830             :         /* make coverity happy */
     831           0 :         assert(attr.aspath);
     832             : 
     833           0 :         attr.med = 0;
     834           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
     835             : 
     836           0 :         if ((afi == AFI_IP6) || peer_cap_enhe(peer, afi, safi)) {
     837             :                 /* IPv6 global nexthop must be included. */
     838           0 :                 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
     839             : 
     840             :                 /* If the peer is on shared nextwork and we have link-local
     841             :                    nexthop set it. */
     842           0 :                 if (peer->shared_network
     843           0 :                     && !IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_local))
     844           0 :                         attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
     845             :         }
     846             : 
     847           0 :         if (peer->default_rmap[afi][safi].name) {
     848           0 :                 struct bgp_path_info tmp_pi = {0};
     849             : 
     850           0 :                 tmp_pi.peer = bgp->peer_self;
     851             : 
     852           0 :                 SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
     853             : 
     854             :                 /* Iterate over the RIB to see if we can announce
     855             :                  * the default route. We announce the default
     856             :                  * route only if route-map has a match.
     857             :                  */
     858           0 :                 for (dest = bgp_table_top(bgp->rib[afi][safi_rib]); dest;
     859           0 :                      dest = bgp_route_next(dest)) {
     860           0 :                         if (!bgp_dest_has_bgp_path_info_data(dest))
     861           0 :                                 continue;
     862             : 
     863           0 :                         for (pi = bgp_dest_get_bgp_path_info(dest); pi;
     864           0 :                              pi = pi->next) {
     865           0 :                                 struct attr tmp_attr = attr;
     866             : 
     867           0 :                                 tmp_pi.attr = &tmp_attr;
     868             : 
     869           0 :                                 new_ret = route_map_apply_ext(
     870             :                                         peer->default_rmap[afi][safi].map,
     871             :                                         bgp_dest_get_prefix(dest), pi, &tmp_pi,
     872             :                                         &new_pref);
     873             : 
     874           0 :                                 if (new_ret == RMAP_PERMITMATCH) {
     875           0 :                                         if (new_pref < pref) {
     876           0 :                                                 pref = new_pref;
     877           0 :                                                 bgp_attr_flush(new_attr);
     878           0 :                                                 new_attr = bgp_attr_intern(
     879             :                                                         tmp_pi.attr);
     880           0 :                                                 bgp_attr_flush(tmp_pi.attr);
     881             :                                         }
     882           0 :                                         subgroup_announce_reset_nhop(
     883           0 :                                                 (peer_cap_enhe(peer, afi, safi)
     884             :                                                          ? AF_INET6
     885             :                                                          : AF_INET),
     886             :                                                 new_attr);
     887           0 :                                         ret = new_ret;
     888             :                                 } else
     889           0 :                                         bgp_attr_flush(&tmp_attr);
     890             :                         }
     891             :                 }
     892           0 :                 bgp->peer_self->rmap_type = 0;
     893             : 
     894           0 :                 if (ret == RMAP_DENYMATCH) {
     895             :                         /*
     896             :                          * If its a implicit withdraw due to routemap
     897             :                          * deny operation need to set the flag back.
     898             :                          * This is a convertion of update flow to
     899             :                          * withdraw flow.
     900             :                          */
     901           0 :                         if (!withdraw &&
     902           0 :                             (!CHECK_FLAG(subgrp->sflags,
     903             :                                          SUBGRP_STATUS_DEFAULT_ORIGINATE)))
     904           0 :                                 SET_FLAG(subgrp->sflags,
     905             :                                          SUBGRP_STATUS_DEFAULT_ORIGINATE);
     906             :                         withdraw = 1;
     907             :                 }
     908             :         }
     909             : 
     910             :         /* Check if the default route is in local BGP RIB which is
     911             :          * installed through redistribute or network command
     912             :          */
     913           0 :         memset(&p, 0, sizeof(p));
     914           0 :         p.family = afi2family(afi);
     915           0 :         p.prefixlen = 0;
     916           0 :         dest = bgp_afi_node_lookup(bgp->rib[afi][safi_rib], afi, safi_rib, &p,
     917             :                                    NULL);
     918             : 
     919           0 :         if (withdraw) {
     920             :                 /* Withdraw the default route advertised using default
     921             :                  * originate
     922             :                  */
     923           0 :                 if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
     924           0 :                         subgroup_default_withdraw_packet(subgrp);
     925           0 :                 UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
     926             : 
     927             :                 /* If default route is present in the local RIB, advertise the
     928             :                  * route
     929             :                  */
     930           0 :                 if (dest) {
     931           0 :                         for (pi = bgp_dest_get_bgp_path_info(dest); pi;
     932           0 :                              pi = pi->next) {
     933           0 :                                 if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
     934           0 :                                         if (subgroup_announce_check(
     935             :                                                     dest, pi, subgrp,
     936             :                                                     bgp_dest_get_prefix(dest),
     937             :                                                     &attr, NULL))
     938           0 :                                                 bgp_adj_out_set_subgroup(
     939             :                                                         dest, subgrp, &attr,
     940             :                                                         pi);
     941             :                         }
     942           0 :                         bgp_dest_unlock_node(dest);
     943             :                 }
     944             :         } else {
     945           0 :                 if (!CHECK_FLAG(subgrp->sflags,
     946             :                                 SUBGRP_STATUS_DEFAULT_ORIGINATE)) {
     947             : 
     948             :                         /* The 'neighbor x.x.x.x default-originate' default will
     949             :                          * act as an
     950             :                          * implicit withdraw for any previous UPDATEs sent for
     951             :                          * 0.0.0.0/0 so
     952             :                          * clear adj_out for the 0.0.0.0/0 prefix in the BGP
     953             :                          * table.
     954             :                          */
     955           0 :                         if (dest) {
     956             :                                 /* Remove the adjacency for the previously
     957             :                                  * advertised default route
     958             :                                  */
     959           0 :                                 adj = adj_lookup(
     960             :                                        dest, subgrp,
     961             :                                        BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
     962           0 :                                 if (adj != NULL) {
     963             :                                         /* Clean up previous advertisement.  */
     964           0 :                                         if (adj->adv)
     965           0 :                                                 bgp_advertise_clean_subgroup(
     966             :                                                         subgrp, adj);
     967             : 
     968             :                                         /* Free allocated information.  */
     969           0 :                                         adj_free(adj);
     970             :                                 }
     971           0 :                                 bgp_dest_unlock_node(dest);
     972             :                         }
     973             : 
     974             :                         /* Advertise the default route */
     975           0 :                         if (bgp_in_graceful_shutdown(bgp))
     976           0 :                                 bgp_attr_add_gshut_community(new_attr);
     977             : 
     978           0 :                         SET_FLAG(subgrp->sflags,
     979             :                                  SUBGRP_STATUS_DEFAULT_ORIGINATE);
     980           0 :                         subgroup_default_update_packet(subgrp, new_attr, from);
     981             :                 }
     982             :         }
     983             : 
     984           0 :         aspath_unintern(&attr.aspath);
     985             : }
     986             : 
     987             : /*
     988             :  * Announce the BGP table to a subgroup.
     989             :  *
     990             :  * At startup, we try to optimize route announcement by coalescing the
     991             :  * peer-up events. This is done only the first time - from then on,
     992             :  * subgrp->v_coalesce will be set to zero and the normal logic
     993             :  * prevails.
     994             :  */
     995           2 : void subgroup_announce_all(struct update_subgroup *subgrp)
     996             : {
     997           2 :         if (!subgrp)
     998             :                 return;
     999             : 
    1000             :         /*
    1001             :          * If coalesce timer value is not set, announce routes immediately.
    1002             :          */
    1003           2 :         if (!subgrp->v_coalesce) {
    1004           0 :                 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
    1005           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64" announcing all routes",
    1006             :                                    subgrp->update_group->id, subgrp->id);
    1007           0 :                 subgroup_announce_route(subgrp);
    1008           0 :                 return;
    1009             :         }
    1010             : 
    1011             :         /*
    1012             :          * We should wait for the coalesce timer. Arm the timer if not done.
    1013             :          */
    1014           2 :         if (!subgrp->t_coalesce) {
    1015           1 :                 thread_add_timer_msec(bm->master, subgroup_coalesce_timer,
    1016             :                                       subgrp, subgrp->v_coalesce,
    1017             :                                       &subgrp->t_coalesce);
    1018             :         }
    1019             : }
    1020             : 
    1021             : /*
    1022             :  * Go through all update subgroups and set up the adv queue for the
    1023             :  * input route.
    1024             :  */
    1025           0 : void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi,
    1026             :                           struct bgp_dest *dest, struct bgp_path_info *pi)
    1027             : {
    1028           0 :         struct updwalk_context ctx;
    1029           0 :         ctx.pi = pi;
    1030           0 :         ctx.dest = dest;
    1031             : 
    1032             :         /* If suppress fib is enabled, the route will be advertised when
    1033             :          * FIB status is received
    1034             :          */
    1035           0 :         if (!bgp_check_advertise(bgp, dest))
    1036           0 :                 return;
    1037             : 
    1038           0 :         update_group_af_walk(bgp, afi, safi, group_announce_route_walkcb, &ctx);
    1039             : }
    1040             : 
    1041           0 : void update_group_show_adj_queue(struct bgp *bgp, afi_t afi, safi_t safi,
    1042             :                                  struct vty *vty, uint64_t id)
    1043             : {
    1044           0 :         updgrp_show_adj(bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVQUEUE);
    1045           0 : }
    1046             : 
    1047           0 : void update_group_show_advertised(struct bgp *bgp, afi_t afi, safi_t safi,
    1048             :                                   struct vty *vty, uint64_t id)
    1049             : {
    1050           0 :         updgrp_show_adj(bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVERTISED);
    1051           0 : }
    1052             : 
    1053           0 : void update_group_announce(struct bgp *bgp)
    1054             : {
    1055           0 :         update_group_walk(bgp, update_group_announce_walkcb, NULL);
    1056           0 : }
    1057             : 
    1058           0 : void update_group_announce_rrclients(struct bgp *bgp)
    1059             : {
    1060           0 :         update_group_walk(bgp, update_group_announce_rrc_walkcb, NULL);
    1061           0 : }

Generated by: LCOV version v1.16-topotato