back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_updgrp.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 15 990 1.5 %
Date: 2023-02-24 18:37:25 Functions: 3 62 4.8 %

          Line data    Source code
       1             : /**
       2             :  * bgp_updgrp.c: BGP update group structures
       3             :  *
       4             :  * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
       5             :  *
       6             :  * @author Avneesh Sachdev <avneesh@sproute.net>
       7             :  * @author Rajesh Varadarajan <rajesh@sproute.net>
       8             :  * @author Pradosh Mohapatra <pradosh@sproute.net>
       9             :  *
      10             :  * This file is part of GNU Zebra.
      11             :  *
      12             :  * GNU Zebra is free software; you can redistribute it and/or modify it
      13             :  * under the terms of the GNU General Public License as published by the
      14             :  * Free Software Foundation; either version 2, or (at your option) any
      15             :  * later version.
      16             :  *
      17             :  * GNU Zebra is distributed in the hope that it will be useful, but
      18             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20             :  * General Public License for more details.
      21             :  *
      22             :  * You should have received a copy of the GNU General Public License along
      23             :  * with this program; see the file COPYING; if not, write to the Free Software
      24             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      25             :  */
      26             : 
      27             : #include <zebra.h>
      28             : 
      29             : #include "prefix.h"
      30             : #include "thread.h"
      31             : #include "buffer.h"
      32             : #include "stream.h"
      33             : #include "command.h"
      34             : #include "sockunion.h"
      35             : #include "network.h"
      36             : #include "memory.h"
      37             : #include "filter.h"
      38             : #include "routemap.h"
      39             : #include "log.h"
      40             : #include "plist.h"
      41             : #include "linklist.h"
      42             : #include "workqueue.h"
      43             : #include "hash.h"
      44             : #include "jhash.h"
      45             : #include "queue.h"
      46             : 
      47             : #include "bgpd/bgpd.h"
      48             : #include "bgpd/bgp_table.h"
      49             : #include "bgpd/bgp_debug.h"
      50             : #include "bgpd/bgp_errors.h"
      51             : #include "bgpd/bgp_fsm.h"
      52             : #include "bgpd/bgp_addpath.h"
      53             : #include "bgpd/bgp_advertise.h"
      54             : #include "bgpd/bgp_packet.h"
      55             : #include "bgpd/bgp_updgrp.h"
      56             : #include "bgpd/bgp_route.h"
      57             : #include "bgpd/bgp_filter.h"
      58             : #include "bgpd/bgp_io.h"
      59             : 
      60             : /********************
      61             :  * PRIVATE FUNCTIONS
      62             :  ********************/
      63             : 
      64             : /**
      65             :  * assign a unique ID to update group and subgroup. Mostly for display/
      66             :  * debugging purposes. It's a 64-bit space - used leisurely without a
      67             :  * worry about its wrapping and about filling gaps. While at it, timestamp
      68             :  * the creation.
      69             :  */
      70           0 : static void update_group_checkin(struct update_group *updgrp)
      71             : {
      72           0 :         updgrp->id = ++bm->updgrp_idspace;
      73           0 :         updgrp->uptime = monotime(NULL);
      74           0 : }
      75             : 
      76           0 : static void update_subgroup_checkin(struct update_subgroup *subgrp,
      77             :                                     struct update_group *updgrp)
      78             : {
      79           0 :         subgrp->id = ++bm->subgrp_idspace;
      80           0 :         subgrp->uptime = monotime(NULL);
      81           0 : }
      82             : 
      83           0 : static void sync_init(struct update_subgroup *subgrp,
      84             :                       struct update_group *updgrp)
      85             : {
      86           0 :         struct peer *peer = UPDGRP_PEER(updgrp);
      87             : 
      88           0 :         subgrp->sync =
      89           0 :                 XCALLOC(MTYPE_BGP_SYNCHRONISE, sizeof(struct bgp_synchronize));
      90           0 :         bgp_adv_fifo_init(&subgrp->sync->update);
      91           0 :         bgp_adv_fifo_init(&subgrp->sync->withdraw);
      92           0 :         bgp_adv_fifo_init(&subgrp->sync->withdraw_low);
      93           0 :         subgrp->hash =
      94           0 :                 hash_create(bgp_advertise_attr_hash_key,
      95             :                             bgp_advertise_attr_hash_cmp, "BGP SubGroup Hash");
      96             : 
      97             :         /* We use a larger buffer for subgrp->work in the event that:
      98             :          * - We RX a BGP_UPDATE where the attributes alone are just
      99             :          *   under 4096 or 65535 (if Extended Message capability negotiated).
     100             :          * - The user configures an outbound route-map that does many as-path
     101             :          *   prepends or adds many communities.  At most they can have
     102             :          * CMD_ARGC_MAX
     103             :          *   args in a route-map so there is a finite limit on how large they
     104             :          * can
     105             :          *   make the attributes.
     106             :          *
     107             :          * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
     108             :          * bounds
     109             :          * checking for every single attribute as we construct an UPDATE.
     110             :          */
     111           0 :         subgrp->work = stream_new(peer->max_packet_size
     112           0 :                                   + BGP_MAX_PACKET_SIZE_OVERFLOW);
     113           0 :         subgrp->scratch = stream_new(peer->max_packet_size);
     114           0 : }
     115             : 
     116           0 : static void sync_delete(struct update_subgroup *subgrp)
     117             : {
     118           0 :         XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
     119           0 :         if (subgrp->hash) {
     120           0 :                 hash_clean(subgrp->hash,
     121             :                            (void (*)(void *))bgp_advertise_attr_free);
     122           0 :                 hash_free(subgrp->hash);
     123             :         }
     124           0 :         subgrp->hash = NULL;
     125           0 :         if (subgrp->work)
     126           0 :                 stream_free(subgrp->work);
     127           0 :         subgrp->work = NULL;
     128           0 :         if (subgrp->scratch)
     129           0 :                 stream_free(subgrp->scratch);
     130           0 :         subgrp->scratch = NULL;
     131           0 : }
     132             : 
     133             : /**
     134             :  * conf_copy
     135             :  *
     136             :  * copy only those fields that are relevant to update group match
     137             :  */
     138           0 : static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
     139             :                       safi_t safi)
     140             : {
     141           0 :         struct bgp_filter *srcfilter;
     142           0 :         struct bgp_filter *dstfilter;
     143             : 
     144           0 :         srcfilter = &src->filter[afi][safi];
     145           0 :         dstfilter = &dst->filter[afi][safi];
     146             : 
     147           0 :         dst->bgp = src->bgp;
     148           0 :         dst->sort = src->sort;
     149           0 :         dst->as = src->as;
     150           0 :         dst->v_routeadv = src->v_routeadv;
     151           0 :         dst->flags = src->flags;
     152           0 :         dst->af_flags[afi][safi] = src->af_flags[afi][safi];
     153           0 :         dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
     154           0 :         dst->max_packet_size = src->max_packet_size;
     155           0 :         XFREE(MTYPE_BGP_PEER_HOST, dst->host);
     156             : 
     157           0 :         dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);
     158           0 :         dst->cap = src->cap;
     159           0 :         dst->af_cap[afi][safi] = src->af_cap[afi][safi];
     160           0 :         dst->afc_nego[afi][safi] = src->afc_nego[afi][safi];
     161           0 :         dst->orf_plist[afi][safi] = src->orf_plist[afi][safi];
     162           0 :         dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
     163           0 :         dst->local_as = src->local_as;
     164           0 :         dst->change_local_as = src->change_local_as;
     165           0 :         dst->shared_network = src->shared_network;
     166           0 :         dst->local_role = src->local_role;
     167           0 :         dst->as_path_loop_detection = src->as_path_loop_detection;
     168             : 
     169           0 :         if (src->soo[afi][safi]) {
     170           0 :                 ecommunity_free(&dst->soo[afi][safi]);
     171           0 :                 dst->soo[afi][safi] = ecommunity_dup(src->soo[afi][safi]);
     172             :         }
     173             : 
     174           0 :         memcpy(&(dst->nexthop), &(src->nexthop), sizeof(struct bgp_nexthop));
     175             : 
     176           0 :         dst->group = src->group;
     177             : 
     178           0 :         if (src->default_rmap[afi][safi].name) {
     179           0 :                 dst->default_rmap[afi][safi].name =
     180           0 :                         XSTRDUP(MTYPE_ROUTE_MAP_NAME,
     181             :                                 src->default_rmap[afi][safi].name);
     182           0 :                 dst->default_rmap[afi][safi].map =
     183           0 :                         src->default_rmap[afi][safi].map;
     184             :         }
     185             : 
     186           0 :         if (DISTRIBUTE_OUT_NAME(srcfilter)) {
     187           0 :                 DISTRIBUTE_OUT_NAME(dstfilter) = XSTRDUP(
     188             :                         MTYPE_BGP_FILTER_NAME, DISTRIBUTE_OUT_NAME(srcfilter));
     189           0 :                 DISTRIBUTE_OUT(dstfilter) = DISTRIBUTE_OUT(srcfilter);
     190             :         }
     191             : 
     192           0 :         if (PREFIX_LIST_OUT_NAME(srcfilter)) {
     193           0 :                 PREFIX_LIST_OUT_NAME(dstfilter) = XSTRDUP(
     194             :                         MTYPE_BGP_FILTER_NAME, PREFIX_LIST_OUT_NAME(srcfilter));
     195           0 :                 PREFIX_LIST_OUT(dstfilter) = PREFIX_LIST_OUT(srcfilter);
     196             :         }
     197             : 
     198           0 :         if (FILTER_LIST_OUT_NAME(srcfilter)) {
     199           0 :                 FILTER_LIST_OUT_NAME(dstfilter) = XSTRDUP(
     200             :                         MTYPE_BGP_FILTER_NAME, FILTER_LIST_OUT_NAME(srcfilter));
     201           0 :                 FILTER_LIST_OUT(dstfilter) = FILTER_LIST_OUT(srcfilter);
     202             :         }
     203             : 
     204           0 :         if (ROUTE_MAP_OUT_NAME(srcfilter)) {
     205           0 :                 ROUTE_MAP_OUT_NAME(dstfilter) = XSTRDUP(
     206             :                         MTYPE_BGP_FILTER_NAME, ROUTE_MAP_OUT_NAME(srcfilter));
     207           0 :                 ROUTE_MAP_OUT(dstfilter) = ROUTE_MAP_OUT(srcfilter);
     208             :         }
     209             : 
     210           0 :         if (UNSUPPRESS_MAP_NAME(srcfilter)) {
     211           0 :                 UNSUPPRESS_MAP_NAME(dstfilter) = XSTRDUP(
     212             :                         MTYPE_BGP_FILTER_NAME, UNSUPPRESS_MAP_NAME(srcfilter));
     213           0 :                 UNSUPPRESS_MAP(dstfilter) = UNSUPPRESS_MAP(srcfilter);
     214             :         }
     215             : 
     216           0 :         if (ADVERTISE_MAP_NAME(srcfilter)) {
     217           0 :                 ADVERTISE_MAP_NAME(dstfilter) = XSTRDUP(
     218             :                         MTYPE_BGP_FILTER_NAME, ADVERTISE_MAP_NAME(srcfilter));
     219           0 :                 ADVERTISE_MAP(dstfilter) = ADVERTISE_MAP(srcfilter);
     220           0 :                 ADVERTISE_CONDITION(dstfilter) = ADVERTISE_CONDITION(srcfilter);
     221             :         }
     222             : 
     223           0 :         if (CONDITION_MAP_NAME(srcfilter)) {
     224           0 :                 CONDITION_MAP_NAME(dstfilter) = XSTRDUP(
     225             :                         MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter));
     226           0 :                 CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter);
     227             :         }
     228             : 
     229           0 :         dstfilter->advmap.update_type = srcfilter->advmap.update_type;
     230           0 : }
     231             : 
     232             : /**
     233             :  * since we did a bunch of XSTRDUP's in conf_copy, time to free them up
     234             :  */
     235           0 : static void conf_release(struct peer *src, afi_t afi, safi_t safi)
     236             : {
     237           0 :         struct bgp_filter *srcfilter;
     238             : 
     239           0 :         srcfilter = &src->filter[afi][safi];
     240             : 
     241           0 :         XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name);
     242             : 
     243           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name);
     244             : 
     245           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name);
     246             : 
     247           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->aslist[FILTER_OUT].name);
     248             : 
     249           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name);
     250             : 
     251           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
     252             : 
     253           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.aname);
     254             : 
     255           0 :         XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.cname);
     256             : 
     257           0 :         XFREE(MTYPE_BGP_PEER_HOST, src->host);
     258             : 
     259           0 :         ecommunity_free(&src->soo[afi][safi]);
     260           0 : }
     261             : 
     262           0 : static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
     263             : {
     264           0 :         struct peer *src;
     265           0 :         struct peer *dst;
     266             : 
     267           0 :         if (!updgrp || !paf)
     268             :                 return;
     269             : 
     270           0 :         src = paf->peer;
     271           0 :         dst = updgrp->conf;
     272           0 :         if (!src || !dst)
     273             :                 return;
     274             : 
     275           0 :         updgrp->afi = paf->afi;
     276           0 :         updgrp->safi = paf->safi;
     277           0 :         updgrp->afid = paf->afid;
     278           0 :         updgrp->bgp = src->bgp;
     279             : 
     280           0 :         conf_copy(dst, src, paf->afi, paf->safi);
     281             : }
     282             : 
     283             : /**
     284             :  * auxiliary functions to maintain the hash table.
     285             :  * - updgrp_hash_alloc - to create a new entry, passed to hash_get
     286             :  * - updgrp_hash_key_make - makes the key for update group search
     287             :  * - updgrp_hash_cmp - compare two update groups.
     288             :  */
     289           0 : static void *updgrp_hash_alloc(void *p)
     290             : {
     291           0 :         struct update_group *updgrp;
     292           0 :         const struct update_group *in;
     293             : 
     294           0 :         in = (const struct update_group *)p;
     295           0 :         updgrp = XCALLOC(MTYPE_BGP_UPDGRP, sizeof(struct update_group));
     296           0 :         memcpy(updgrp, in, sizeof(struct update_group));
     297           0 :         updgrp->conf = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer));
     298           0 :         conf_copy(updgrp->conf, in->conf, in->afi, in->safi);
     299           0 :         return updgrp;
     300             : }
     301             : 
     302             : /**
     303             :  * The hash value for a peer is computed from the following variables:
     304             :  * v = f(
     305             :  *       1. IBGP (1) or EBGP (2)
     306             :  *       2. FLAGS based on configuration:
     307             :  *             LOCAL_AS_NO_PREPEND
     308             :  *             LOCAL_AS_REPLACE_AS
     309             :  *       3. AF_FLAGS based on configuration:
     310             :  *             Refer to definition in bgp_updgrp.h
     311             :  *       4. (AF-independent) Capability flags:
     312             :  *             AS4_RCV capability
     313             :  *       5. (AF-dependent) Capability flags:
     314             :  *             ORF_PREFIX_SM_RCV (peer can send prefix ORF)
     315             :  *       6. MRAI
     316             :  *       7. peer-group name
     317             :  *       8. Outbound route-map name (neighbor route-map <> out)
     318             :  *       9. Outbound distribute-list name (neighbor distribute-list <> out)
     319             :  *       10. Outbound prefix-list name (neighbor prefix-list <> out)
     320             :  *       11. Outbound as-list name (neighbor filter-list <> out)
     321             :  *       12. Unsuppress map name (neighbor unsuppress-map <>)
     322             :  *       13. default rmap name (neighbor default-originate route-map <>)
     323             :  *       14. encoding both global and link-local nexthop?
     324             :  *       15. If peer is configured to be a lonesoul, peer ip address
     325             :  *       16. Local-as should match, if configured.
     326             :  *       17. maximum-prefix-out
     327             :  *       18. Local-role should also match, if configured.
     328             :  *      )
     329             :  */
     330           0 : static unsigned int updgrp_hash_key_make(const void *p)
     331             : {
     332           0 :         const struct update_group *updgrp;
     333           0 :         const struct peer *peer;
     334           0 :         const struct bgp_filter *filter;
     335           0 :         uint32_t flags;
     336           0 :         uint32_t key;
     337           0 :         afi_t afi;
     338           0 :         safi_t safi;
     339             : 
     340             : #define SEED1 999331
     341             : #define SEED2 2147483647
     342             : 
     343           0 :         updgrp = p;
     344           0 :         peer = updgrp->conf;
     345           0 :         afi = updgrp->afi;
     346           0 :         safi = updgrp->safi;
     347           0 :         flags = peer->af_flags[afi][safi];
     348           0 :         filter = &peer->filter[afi][safi];
     349             : 
     350           0 :         key = 0;
     351             : 
     352           0 :         key = jhash_1word(peer->sort, key); /* EBGP or IBGP */
     353           0 :         key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
     354           0 :         key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
     355           0 :         key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
     356           0 :         key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
     357           0 :         key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
     358             :                           key);
     359           0 :         key = jhash_1word(peer->v_routeadv, key);
     360           0 :         key = jhash_1word(peer->change_local_as, key);
     361           0 :         key = jhash_1word(peer->max_packet_size, key);
     362           0 :         key = jhash_1word(peer->pmax_out[afi][safi], key);
     363             : 
     364           0 :         if (peer->as_path_loop_detection)
     365           0 :                 key = jhash_2words(peer->as, peer->as_path_loop_detection, key);
     366             : 
     367           0 :         if (peer->group)
     368           0 :                 key = jhash_1word(jhash(peer->group->name,
     369           0 :                                         strlen(peer->group->name), SEED1),
     370             :                                   key);
     371             : 
     372           0 :         if (filter->map[RMAP_OUT].name)
     373           0 :                 key = jhash_1word(jhash(filter->map[RMAP_OUT].name,
     374           0 :                                         strlen(filter->map[RMAP_OUT].name),
     375             :                                         SEED1),
     376             :                                   key);
     377             : 
     378           0 :         if (filter->dlist[FILTER_OUT].name)
     379           0 :                 key = jhash_1word(jhash(filter->dlist[FILTER_OUT].name,
     380           0 :                                         strlen(filter->dlist[FILTER_OUT].name),
     381             :                                         SEED1),
     382             :                                   key);
     383             : 
     384           0 :         if (filter->plist[FILTER_OUT].name)
     385           0 :                 key = jhash_1word(jhash(filter->plist[FILTER_OUT].name,
     386           0 :                                         strlen(filter->plist[FILTER_OUT].name),
     387             :                                         SEED1),
     388             :                                   key);
     389             : 
     390           0 :         if (filter->aslist[FILTER_OUT].name)
     391           0 :                 key = jhash_1word(jhash(filter->aslist[FILTER_OUT].name,
     392           0 :                                         strlen(filter->aslist[FILTER_OUT].name),
     393             :                                         SEED1),
     394             :                                   key);
     395             : 
     396           0 :         if (filter->usmap.name)
     397           0 :                 key = jhash_1word(jhash(filter->usmap.name,
     398           0 :                                         strlen(filter->usmap.name), SEED1),
     399             :                                   key);
     400             : 
     401           0 :         if (filter->advmap.aname)
     402           0 :                 key = jhash_1word(jhash(filter->advmap.aname,
     403           0 :                                         strlen(filter->advmap.aname), SEED1),
     404             :                                   key);
     405             : 
     406           0 :         if (filter->advmap.update_type)
     407           0 :                 key = jhash_1word(filter->advmap.update_type, key);
     408             : 
     409           0 :         if (peer->default_rmap[afi][safi].name)
     410           0 :                 key = jhash_1word(
     411             :                         jhash(peer->default_rmap[afi][safi].name,
     412           0 :                               strlen(peer->default_rmap[afi][safi].name),
     413             :                               SEED1),
     414             :                         key);
     415             : 
     416             :         /* If peer is on a shared network and is exchanging IPv6 prefixes,
     417             :          * it needs to include link-local address. That's different from
     418             :          * non-shared-network peers (nexthop encoded with 32 bytes vs 16
     419             :          * bytes). We create different update groups to take care of that.
     420             :          */
     421           0 :         key = jhash_1word(
     422           0 :                 (peer->shared_network && peer_afi_active_nego(peer, AFI_IP6)),
     423             :                 key);
     424             :         /*
     425             :          * There are certain peers that must get their own update-group:
     426             :          * - lonesoul peers
     427             :          * - peers that negotiated ORF
     428             :          * - maximum-prefix-out is set
     429             :          */
     430           0 :         if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)
     431           0 :             || CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
     432           0 :             || CHECK_FLAG(peer->af_cap[afi][safi],
     433             :                           PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
     434           0 :             || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
     435           0 :                 key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2),
     436             :                                   key);
     437             :         /*
     438             :          * Multiple sessions with the same neighbor should get their own
     439             :          * update-group if they have different roles.
     440             :          */
     441           0 :         key = jhash_1word(peer->local_role, key);
     442             : 
     443             :         /* Neighbors configured with the AIGP attribute are put in a separate
     444             :          * update group from other neighbors.
     445             :          */
     446           0 :         key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
     447             : 
     448           0 :         if (peer->soo[afi][safi]) {
     449           0 :                 char *soo_str = ecommunity_str(peer->soo[afi][safi]);
     450             : 
     451           0 :                 key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key);
     452             :         }
     453             : 
     454           0 :         if (bgp_debug_neighbor_events(peer)) {
     455           0 :                 zlog_debug(
     456             :                         "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju",
     457             :                         peer, peer->sort,
     458             :                         (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS),
     459             :                         (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS));
     460           0 :                 zlog_debug(
     461             :                         "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d",
     462             :                         peer, (uint32_t)peer->addpath_type[afi][safi],
     463             :                         CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS),
     464             :                         CHECK_FLAG(peer->af_cap[afi][safi],
     465             :                                    PEER_UPDGRP_AF_CAP_FLAGS),
     466             :                         peer->v_routeadv, peer->change_local_as,
     467             :                         peer->as_path_loop_detection);
     468           0 :                 zlog_debug(
     469             :                         "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
     470             :                         peer, peer->max_packet_size, peer->pmax_out[afi][safi],
     471             :                         peer->group ? peer->group->name : "(NONE)",
     472             :                         ROUTE_MAP_OUT_NAME(filter) ? ROUTE_MAP_OUT_NAME(filter)
     473             :                                                    : "(NONE)");
     474           0 :                 zlog_debug(
     475             :                         "%pBP Update Group Hash: dlist out: %s plist out: %s aslist out: %s usmap out: %s advmap: %s",
     476             :                         peer,
     477             :                         DISTRIBUTE_OUT_NAME(filter)
     478             :                                 ? DISTRIBUTE_OUT_NAME(filter)
     479             :                                 : "(NONE)",
     480             :                         PREFIX_LIST_OUT_NAME(filter)
     481             :                                 ? PREFIX_LIST_OUT_NAME(filter)
     482             :                                 : "(NONE)",
     483             :                         FILTER_LIST_OUT_NAME(filter)
     484             :                                 ? FILTER_LIST_OUT_NAME(filter)
     485             :                                 : "(NONE)",
     486             :                         UNSUPPRESS_MAP_NAME(filter)
     487             :                                 ? UNSUPPRESS_MAP_NAME(filter)
     488             :                                 : "(NONE)",
     489             :                         ADVERTISE_MAP_NAME(filter) ? ADVERTISE_MAP_NAME(filter)
     490             :                                                    : "(NONE)");
     491           0 :                 zlog_debug(
     492             :                         "%pBP Update Group Hash: default rmap: %s shared network and afi active network: %d",
     493             :                         peer,
     494             :                         peer->default_rmap[afi][safi].name
     495             :                                 ? peer->default_rmap[afi][safi].name
     496             :                                 : "(NONE)",
     497             :                         peer->shared_network &&
     498             :                                 peer_afi_active_nego(peer, AFI_IP6));
     499           0 :                 zlog_debug(
     500             :                         "%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u ORF old: %u max prefix out: %ju",
     501             :                         peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL),
     502             :                         CHECK_FLAG(peer->af_cap[afi][safi],
     503             :                                    PEER_CAP_ORF_PREFIX_SM_RCV),
     504             :                         CHECK_FLAG(peer->af_cap[afi][safi],
     505             :                                    PEER_CAP_ORF_PREFIX_SM_OLD_RCV),
     506             :                         (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi],
     507             :                                              PEER_FLAG_MAX_PREFIX_OUT));
     508           0 :                 zlog_debug("%pBP Update Group Hash key: %u", peer, key);
     509             :         }
     510           0 :         return key;
     511             : }
     512             : 
     513           0 : static bool updgrp_hash_cmp(const void *p1, const void *p2)
     514             : {
     515           0 :         const struct update_group *grp1;
     516           0 :         const struct update_group *grp2;
     517           0 :         const struct peer *pe1;
     518           0 :         const struct peer *pe2;
     519           0 :         uint32_t flags1;
     520           0 :         uint32_t flags2;
     521           0 :         const struct bgp_filter *fl1;
     522           0 :         const struct bgp_filter *fl2;
     523           0 :         afi_t afi;
     524           0 :         safi_t safi;
     525             : 
     526           0 :         if (!p1 || !p2)
     527             :                 return false;
     528             : 
     529           0 :         grp1 = p1;
     530           0 :         grp2 = p2;
     531           0 :         pe1 = grp1->conf;
     532           0 :         pe2 = grp2->conf;
     533           0 :         afi = grp1->afi;
     534           0 :         safi = grp1->safi;
     535           0 :         flags1 = pe1->af_flags[afi][safi];
     536           0 :         flags2 = pe2->af_flags[afi][safi];
     537           0 :         fl1 = &pe1->filter[afi][safi];
     538           0 :         fl2 = &pe2->filter[afi][safi];
     539             : 
     540             :         /* put EBGP and IBGP peers in different update groups */
     541           0 :         if (pe1->sort != pe2->sort)
     542             :                 return false;
     543             : 
     544             :         /* check peer flags */
     545           0 :         if ((pe1->flags & PEER_UPDGRP_FLAGS)
     546           0 :             != (pe2->flags & PEER_UPDGRP_FLAGS))
     547             :                 return false;
     548             : 
     549             :         /* If there is 'local-as' configured, it should match. */
     550           0 :         if (pe1->change_local_as != pe2->change_local_as)
     551             :                 return false;
     552             : 
     553           0 :         if (pe1->pmax_out[afi][safi] != pe2->pmax_out[afi][safi])
     554             :                 return false;
     555             : 
     556             :         /* flags like route reflector client */
     557           0 :         if ((flags1 & PEER_UPDGRP_AF_FLAGS) != (flags2 & PEER_UPDGRP_AF_FLAGS))
     558             :                 return false;
     559             : 
     560           0 :         if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi])
     561             :                 return false;
     562             : 
     563           0 :         if ((pe1->cap & PEER_UPDGRP_CAP_FLAGS)
     564           0 :             != (pe2->cap & PEER_UPDGRP_CAP_FLAGS))
     565             :                 return false;
     566             : 
     567           0 :         if ((pe1->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS)
     568           0 :             != (pe2->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS))
     569             :                 return false;
     570             : 
     571           0 :         if (pe1->v_routeadv != pe2->v_routeadv)
     572             :                 return false;
     573             : 
     574           0 :         if (pe1->group != pe2->group)
     575             :                 return false;
     576             : 
     577             :         /* Roles can affect filtering */
     578           0 :         if (pe1->local_role != pe2->local_role)
     579             :                 return false;
     580             : 
     581             :         /* route-map names should be the same */
     582           0 :         if ((fl1->map[RMAP_OUT].name && !fl2->map[RMAP_OUT].name)
     583           0 :             || (!fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name)
     584           0 :             || (fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name
     585           0 :                 && strcmp(fl1->map[RMAP_OUT].name, fl2->map[RMAP_OUT].name)))
     586             :                 return false;
     587             : 
     588           0 :         if ((fl1->dlist[FILTER_OUT].name && !fl2->dlist[FILTER_OUT].name)
     589           0 :             || (!fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name)
     590           0 :             || (fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name
     591           0 :                 && strcmp(fl1->dlist[FILTER_OUT].name,
     592             :                           fl2->dlist[FILTER_OUT].name)))
     593             :                 return false;
     594             : 
     595           0 :         if ((fl1->plist[FILTER_OUT].name && !fl2->plist[FILTER_OUT].name)
     596           0 :             || (!fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name)
     597           0 :             || (fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name
     598           0 :                 && strcmp(fl1->plist[FILTER_OUT].name,
     599             :                           fl2->plist[FILTER_OUT].name)))
     600             :                 return false;
     601             : 
     602           0 :         if ((fl1->aslist[FILTER_OUT].name && !fl2->aslist[FILTER_OUT].name)
     603           0 :             || (!fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name)
     604           0 :             || (fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name
     605           0 :                 && strcmp(fl1->aslist[FILTER_OUT].name,
     606             :                           fl2->aslist[FILTER_OUT].name)))
     607             :                 return false;
     608             : 
     609           0 :         if ((fl1->usmap.name && !fl2->usmap.name)
     610           0 :             || (!fl1->usmap.name && fl2->usmap.name)
     611           0 :             || (fl1->usmap.name && fl2->usmap.name
     612           0 :                 && strcmp(fl1->usmap.name, fl2->usmap.name)))
     613             :                 return false;
     614             : 
     615           0 :         if ((fl1->advmap.aname && !fl2->advmap.aname)
     616           0 :             || (!fl1->advmap.aname && fl2->advmap.aname)
     617           0 :             || (fl1->advmap.aname && fl2->advmap.aname
     618           0 :                 && strcmp(fl1->advmap.aname, fl2->advmap.aname)))
     619             :                 return false;
     620             : 
     621           0 :         if (fl1->advmap.update_type != fl2->advmap.update_type)
     622             :                 return false;
     623             : 
     624           0 :         if ((pe1->default_rmap[afi][safi].name
     625           0 :              && !pe2->default_rmap[afi][safi].name)
     626           0 :             || (!pe1->default_rmap[afi][safi].name
     627           0 :                 && pe2->default_rmap[afi][safi].name)
     628           0 :             || (pe1->default_rmap[afi][safi].name
     629           0 :                 && pe2->default_rmap[afi][safi].name
     630           0 :                 && strcmp(pe1->default_rmap[afi][safi].name,
     631             :                           pe2->default_rmap[afi][safi].name)))
     632             :                 return false;
     633             : 
     634           0 :         if ((afi == AFI_IP6) && (pe1->shared_network != pe2->shared_network))
     635             :                 return false;
     636             : 
     637           0 :         if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL)
     638           0 :              || CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
     639           0 :              || CHECK_FLAG(pe1->af_cap[afi][safi],
     640             :                            PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
     641           0 :             && !sockunion_same(&pe1->su, &pe2->su))
     642             :                 return false;
     643             : 
     644             :         return true;
     645             : }
     646             : 
     647           0 : static void peer_lonesoul_or_not(struct peer *peer, int set)
     648             : {
     649             :         /* no change in status? */
     650           0 :         if (set == (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL) > 0))
     651             :                 return;
     652             : 
     653           0 :         if (set)
     654           0 :                 SET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
     655             :         else
     656           0 :                 UNSET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
     657             : 
     658           0 :         update_group_adjust_peer_afs(peer);
     659             : }
     660             : 
     661             : /*
     662             :  * subgroup_total_packets_enqueued
     663             :  *
     664             :  * Returns the total number of packets enqueued to a subgroup.
     665             :  */
     666             : static unsigned int
     667           0 : subgroup_total_packets_enqueued(struct update_subgroup *subgrp)
     668             : {
     669           0 :         struct bpacket *pkt;
     670             : 
     671           0 :         pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
     672             : 
     673           0 :         return pkt->ver - 1;
     674             : }
     675             : 
     676           0 : static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
     677             : {
     678           0 :         struct updwalk_context *ctx = arg;
     679           0 :         struct vty *vty;
     680           0 :         struct update_subgroup *subgrp;
     681           0 :         struct peer_af *paf;
     682           0 :         struct bgp_filter *filter;
     683           0 :         struct peer *peer = UPDGRP_PEER(updgrp);
     684           0 :         int match = 0;
     685           0 :         json_object *json_updgrp = NULL;
     686           0 :         json_object *json_subgrps = NULL;
     687           0 :         json_object *json_subgrp = NULL;
     688           0 :         json_object *json_time = NULL;
     689           0 :         json_object *json_subgrp_time = NULL;
     690           0 :         json_object *json_subgrp_event = NULL;
     691           0 :         json_object *json_peers = NULL;
     692           0 :         json_object *json_pkt_info = NULL;
     693           0 :         time_t epoch_tbuf, tbuf;
     694             : 
     695           0 :         if (!ctx)
     696             :                 return CMD_SUCCESS;
     697             : 
     698           0 :         if (ctx->subgrp_id) {
     699           0 :                 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     700           0 :                         if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
     701           0 :                                 continue;
     702             :                         else {
     703             :                                 match = 1;
     704             :                                 break;
     705             :                         }
     706             :                 }
     707             :         } else {
     708             :                 match = 1;
     709             :         }
     710             : 
     711           0 :         if (!match) {
     712             :                 /* Since this routine is invoked from a walk, we cannot signal
     713             :                  * any */
     714             :                 /* error here, can only return. */
     715             :                 return CMD_SUCCESS;
     716             :         }
     717             : 
     718           0 :         vty = ctx->vty;
     719             : 
     720           0 :         if (ctx->uj) {
     721           0 :                 json_updgrp = json_object_new_object();
     722             :                 /* Display json o/p */
     723           0 :                 tbuf = monotime(NULL);
     724           0 :                 tbuf -= updgrp->uptime;
     725           0 :                 epoch_tbuf = time(NULL) - tbuf;
     726           0 :                 json_time = json_object_new_object();
     727           0 :                 json_object_int_add(json_time, "epoch", epoch_tbuf);
     728           0 :                 json_object_string_add(json_time, "epochString",
     729           0 :                                        ctime(&epoch_tbuf));
     730           0 :                 json_object_object_add(json_updgrp, "groupCreateTime",
     731             :                                        json_time);
     732           0 :                 json_object_string_add(json_updgrp, "afi",
     733             :                                        afi2str(updgrp->afi));
     734           0 :                 json_object_string_add(json_updgrp, "safi",
     735             :                                        safi2str(updgrp->safi));
     736             :         } else {
     737           0 :                 vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
     738           0 :                 vty_out(vty, "  Created: %s", timestamp_string(updgrp->uptime));
     739             :         }
     740             : 
     741           0 :         filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
     742           0 :         if (filter->map[RMAP_OUT].name) {
     743           0 :                 if (ctx->uj)
     744           0 :                         json_object_string_add(json_updgrp, "outRouteMap",
     745             :                                                filter->map[RMAP_OUT].name);
     746             :                 else
     747           0 :                         vty_out(vty, "  Outgoing route map: %s\n",
     748             :                                 filter->map[RMAP_OUT].name);
     749             :         }
     750             : 
     751           0 :         if (ctx->uj)
     752           0 :                 json_object_int_add(json_updgrp, "minRouteAdvInt",
     753           0 :                                     updgrp->conf->v_routeadv);
     754             :         else
     755           0 :                 vty_out(vty, "  MRAI value (seconds): %d\n",
     756           0 :                         updgrp->conf->v_routeadv);
     757             : 
     758           0 :         if (updgrp->conf->change_local_as) {
     759           0 :                 if (ctx->uj) {
     760           0 :                         json_object_int_add(json_updgrp, "localAs",
     761             :                                             updgrp->conf->change_local_as);
     762           0 :                         json_object_boolean_add(
     763             :                                 json_updgrp, "noPrepend",
     764           0 :                                 CHECK_FLAG(updgrp->conf->flags,
     765             :                                            PEER_FLAG_LOCAL_AS_NO_PREPEND));
     766           0 :                         json_object_boolean_add(
     767             :                                 json_updgrp, "replaceLocalAs",
     768           0 :                                 CHECK_FLAG(updgrp->conf->flags,
     769             :                                            PEER_FLAG_LOCAL_AS_REPLACE_AS));
     770             :                 } else {
     771           0 :                         vty_out(vty, "  Local AS %u%s%s\n",
     772             :                                 updgrp->conf->change_local_as,
     773           0 :                                 CHECK_FLAG(updgrp->conf->flags,
     774             :                                            PEER_FLAG_LOCAL_AS_NO_PREPEND)
     775             :                                         ? " no-prepend"
     776             :                                         : "",
     777           0 :                                 CHECK_FLAG(updgrp->conf->flags,
     778             :                                            PEER_FLAG_LOCAL_AS_REPLACE_AS)
     779             :                                         ? " replace-as"
     780             :                                         : "");
     781             :                 }
     782             :         }
     783           0 :         if (ctx->uj)
     784           0 :                 json_subgrps = json_object_new_array();
     785           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     786           0 :                 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
     787           0 :                         continue;
     788           0 :                 if (ctx->uj) {
     789           0 :                         json_subgrp = json_object_new_object();
     790           0 :                         json_object_int_add(json_subgrp, "subGroupId",
     791           0 :                                             subgrp->id);
     792           0 :                         tbuf = monotime(NULL);
     793           0 :                         tbuf -= subgrp->uptime;
     794           0 :                         epoch_tbuf = time(NULL) - tbuf;
     795           0 :                         json_subgrp_time = json_object_new_object();
     796           0 :                         json_object_int_add(json_subgrp_time, "epoch",
     797             :                                             epoch_tbuf);
     798           0 :                         json_object_string_add(json_subgrp_time, "epochString",
     799           0 :                                                ctime(&epoch_tbuf));
     800           0 :                         json_object_object_add(json_subgrp, "groupCreateTime",
     801             :                                                json_subgrp_time);
     802             :                 } else {
     803           0 :                         vty_out(vty, "\n");
     804           0 :                         vty_out(vty, "  Update-subgroup %" PRIu64 ":\n",
     805             :                                 subgrp->id);
     806           0 :                         vty_out(vty, "    Created: %s",
     807             :                                 timestamp_string(subgrp->uptime));
     808             :                 }
     809             : 
     810           0 :                 if (subgrp->split_from.update_group_id
     811           0 :                     || subgrp->split_from.subgroup_id) {
     812           0 :                         if (ctx->uj) {
     813           0 :                                 json_object_int_add(
     814             :                                         json_subgrp, "splitGroupId",
     815             :                                         subgrp->split_from.update_group_id);
     816           0 :                                 json_object_int_add(
     817             :                                         json_subgrp, "splitSubGroupId",
     818           0 :                                         subgrp->split_from.subgroup_id);
     819             :                         } else {
     820           0 :                                 vty_out(vty,
     821             :                                         "    Split from group id: %" PRIu64
     822             :                                         "\n",
     823             :                                         subgrp->split_from.update_group_id);
     824           0 :                                 vty_out(vty,
     825             :                                         "    Split from subgroup id: %" PRIu64
     826             :                                         "\n",
     827             :                                         subgrp->split_from.subgroup_id);
     828             :                         }
     829             :                 }
     830             : 
     831           0 :                 if (ctx->uj) {
     832           0 :                         json_subgrp_event = json_object_new_object();
     833           0 :                         json_object_int_add(json_subgrp_event, "joinEvents",
     834           0 :                                             subgrp->join_events);
     835           0 :                         json_object_int_add(json_subgrp_event, "pruneEvents",
     836           0 :                                             subgrp->prune_events);
     837           0 :                         json_object_int_add(json_subgrp_event, "mergeEvents",
     838           0 :                                             subgrp->merge_events);
     839           0 :                         json_object_int_add(json_subgrp_event, "splitEvents",
     840           0 :                                             subgrp->split_events);
     841           0 :                         json_object_int_add(json_subgrp_event, "switchEvents",
     842           0 :                                             subgrp->updgrp_switch_events);
     843           0 :                         json_object_int_add(json_subgrp_event,
     844             :                                             "peerRefreshEvents",
     845           0 :                                             subgrp->peer_refreshes_combined);
     846           0 :                         json_object_int_add(json_subgrp_event,
     847             :                                             "mergeCheckEvents",
     848           0 :                                             subgrp->merge_checks_triggered);
     849           0 :                         json_object_object_add(json_subgrp, "statistics",
     850             :                                                json_subgrp_event);
     851           0 :                         json_object_int_add(json_subgrp, "coalesceTime",
     852           0 :                                             (UPDGRP_INST(subgrp->update_group))
     853           0 :                                                     ->coalesce_time);
     854           0 :                         json_object_int_add(json_subgrp, "version",
     855           0 :                                             subgrp->version);
     856           0 :                         json_pkt_info = json_object_new_object();
     857           0 :                         json_object_int_add(
     858             :                                 json_pkt_info, "qeueueLen",
     859           0 :                                 bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
     860           0 :                         json_object_int_add(
     861             :                                 json_pkt_info, "queuedTotal",
     862           0 :                                 subgroup_total_packets_enqueued(subgrp));
     863           0 :                         json_object_int_add(
     864             :                                 json_pkt_info, "queueHwmLen",
     865           0 :                                 bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
     866           0 :                         json_object_int_add(
     867             :                                 json_pkt_info, "totalEnqueued",
     868           0 :                                 subgroup_total_packets_enqueued(subgrp));
     869           0 :                         json_object_object_add(json_subgrp, "packetQueueInfo",
     870             :                                                json_pkt_info);
     871           0 :                         json_object_int_add(json_subgrp, "adjListCount",
     872           0 :                                             subgrp->adj_count);
     873           0 :                         json_object_boolean_add(
     874             :                                 json_subgrp, "needsRefresh",
     875           0 :                                 CHECK_FLAG(subgrp->flags,
     876             :                                            SUBGRP_FLAG_NEEDS_REFRESH));
     877             :                 } else {
     878           0 :                         vty_out(vty, "    Join events: %u\n",
     879             :                                 subgrp->join_events);
     880           0 :                         vty_out(vty, "    Prune events: %u\n",
     881             :                                 subgrp->prune_events);
     882           0 :                         vty_out(vty, "    Merge events: %u\n",
     883             :                                 subgrp->merge_events);
     884           0 :                         vty_out(vty, "    Split events: %u\n",
     885             :                                 subgrp->split_events);
     886           0 :                         vty_out(vty, "    Update group switch events: %u\n",
     887             :                                 subgrp->updgrp_switch_events);
     888           0 :                         vty_out(vty, "    Peer refreshes combined: %u\n",
     889             :                                 subgrp->peer_refreshes_combined);
     890           0 :                         vty_out(vty, "    Merge checks triggered: %u\n",
     891             :                                 subgrp->merge_checks_triggered);
     892           0 :                         vty_out(vty, "    Coalesce Time: %u%s\n",
     893           0 :                                 (UPDGRP_INST(subgrp->update_group))
     894             :                                         ->coalesce_time,
     895           0 :                                 subgrp->t_coalesce ? "(Running)" : "");
     896           0 :                         vty_out(vty, "    Version: %" PRIu64 "\n",
     897             :                                 subgrp->version);
     898           0 :                         vty_out(vty, "    Packet queue length: %d\n",
     899             :                                 bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
     900           0 :                         vty_out(vty, "    Total packets enqueued: %u\n",
     901             :                                 subgroup_total_packets_enqueued(subgrp));
     902           0 :                         vty_out(vty, "    Packet queue high watermark: %d\n",
     903             :                                 bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
     904           0 :                         vty_out(vty, "    Adj-out list count: %u\n",
     905             :                                 subgrp->adj_count);
     906           0 :                         vty_out(vty, "    Advertise list: %s\n",
     907           0 :                                 advertise_list_is_empty(subgrp) ? "empty"
     908             :                                                                 : "not empty");
     909           0 :                         vty_out(vty, "    Flags: %s\n",
     910           0 :                                 CHECK_FLAG(subgrp->flags,
     911             :                                            SUBGRP_FLAG_NEEDS_REFRESH)
     912             :                                         ? "R"
     913             :                                         : "");
     914           0 :                         if (peer)
     915           0 :                                 vty_out(vty, "    Max packet size: %d\n",
     916           0 :                                         peer->max_packet_size);
     917             :                 }
     918           0 :                 if (subgrp->peer_count > 0) {
     919           0 :                         if (ctx->uj) {
     920           0 :                                 json_peers = json_object_new_array();
     921           0 :                                 SUBGRP_FOREACH_PEER (subgrp, paf) {
     922           0 :                                         json_object *peer =
     923           0 :                                                 json_object_new_string(
     924           0 :                                                         paf->peer->host);
     925           0 :                                         json_object_array_add(json_peers, peer);
     926             :                                 }
     927           0 :                                 json_object_object_add(json_subgrp, "peers",
     928             :                                                        json_peers);
     929             :                         } else {
     930           0 :                                 vty_out(vty, "    Peers:\n");
     931           0 :                                 SUBGRP_FOREACH_PEER (subgrp, paf)
     932           0 :                                         vty_out(vty, "      - %s\n",
     933           0 :                                                 paf->peer->host);
     934             :                         }
     935             :                 }
     936             : 
     937           0 :                 if (ctx->uj)
     938           0 :                         json_object_array_add(json_subgrps, json_subgrp);
     939             :         }
     940             : 
     941           0 :         if (ctx->uj) {
     942           0 :                 json_object_object_add(json_updgrp, "subGroup", json_subgrps);
     943           0 :                 json_object_object_addf(ctx->json_updategrps, json_updgrp,
     944             :                                         "%" PRIu64, updgrp->id);
     945             :         }
     946             : 
     947             :         return UPDWALK_CONTINUE;
     948             : }
     949             : 
     950             : /*
     951             :  * Helper function to show the packet queue for each subgroup of update group.
     952             :  * Will be constrained to a particular subgroup id if id !=0
     953             :  */
     954           0 : static int updgrp_show_packet_queue_walkcb(struct update_group *updgrp,
     955             :                                            void *arg)
     956             : {
     957           0 :         struct updwalk_context *ctx = arg;
     958           0 :         struct update_subgroup *subgrp;
     959           0 :         struct vty *vty;
     960             : 
     961           0 :         vty = ctx->vty;
     962           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
     963           0 :                 if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
     964           0 :                         continue;
     965           0 :                 vty_out(vty, "update group %" PRIu64 ", subgroup %" PRIu64 "\n",
     966             :                         updgrp->id, subgrp->id);
     967           0 :                 bpacket_queue_show_vty(SUBGRP_PKTQ(subgrp), vty);
     968             :         }
     969           0 :         return UPDWALK_CONTINUE;
     970             : }
     971             : 
     972             : /*
     973             :  * Show the packet queue for each subgroup of update group. Will be
     974             :  * constrained to a particular subgroup id if id !=0
     975             :  */
     976           0 : void update_group_show_packet_queue(struct bgp *bgp, afi_t afi, safi_t safi,
     977             :                                     struct vty *vty, uint64_t id)
     978             : {
     979           0 :         struct updwalk_context ctx;
     980             : 
     981           0 :         memset(&ctx, 0, sizeof(ctx));
     982           0 :         ctx.vty = vty;
     983           0 :         ctx.subgrp_id = id;
     984           0 :         ctx.flags = 0;
     985           0 :         update_group_af_walk(bgp, afi, safi, updgrp_show_packet_queue_walkcb,
     986             :                              &ctx);
     987           0 : }
     988             : 
     989           0 : static struct update_group *update_group_find(struct peer_af *paf)
     990             : {
     991           0 :         struct update_group *updgrp;
     992           0 :         struct update_group tmp;
     993           0 :         struct peer tmp_conf;
     994             : 
     995           0 :         if (!peer_established(PAF_PEER(paf)))
     996             :                 return NULL;
     997             : 
     998           0 :         memset(&tmp, 0, sizeof(tmp));
     999           0 :         memset(&tmp_conf, 0, sizeof(tmp_conf));
    1000           0 :         tmp.conf = &tmp_conf;
    1001           0 :         peer2_updgrp_copy(&tmp, paf);
    1002             : 
    1003           0 :         updgrp = hash_lookup(paf->peer->bgp->update_groups[paf->afid], &tmp);
    1004           0 :         conf_release(&tmp_conf, paf->afi, paf->safi);
    1005           0 :         return updgrp;
    1006             : }
    1007             : 
    1008           0 : static struct update_group *update_group_create(struct peer_af *paf)
    1009             : {
    1010           0 :         struct update_group *updgrp;
    1011           0 :         struct update_group tmp;
    1012           0 :         struct peer tmp_conf;
    1013             : 
    1014           0 :         memset(&tmp, 0, sizeof(tmp));
    1015           0 :         memset(&tmp_conf, 0, sizeof(tmp_conf));
    1016           0 :         tmp.conf = &tmp_conf;
    1017           0 :         peer2_updgrp_copy(&tmp, paf);
    1018             : 
    1019           0 :         updgrp = hash_get(paf->peer->bgp->update_groups[paf->afid], &tmp,
    1020             :                           updgrp_hash_alloc);
    1021           0 :         update_group_checkin(updgrp);
    1022             : 
    1023           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1024           0 :                 zlog_debug("create update group %" PRIu64, updgrp->id);
    1025             : 
    1026           0 :         UPDGRP_GLOBAL_STAT(updgrp, updgrps_created) += 1;
    1027             : 
    1028           0 :         conf_release(&tmp_conf, paf->afi, paf->safi);
    1029           0 :         return updgrp;
    1030             : }
    1031             : 
    1032           0 : static void update_group_delete(struct update_group *updgrp)
    1033             : {
    1034           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1035           0 :                 zlog_debug("delete update group %" PRIu64, updgrp->id);
    1036             : 
    1037           0 :         UPDGRP_GLOBAL_STAT(updgrp, updgrps_deleted) += 1;
    1038             : 
    1039           0 :         hash_release(updgrp->bgp->update_groups[updgrp->afid], updgrp);
    1040           0 :         conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
    1041             : 
    1042           0 :         XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
    1043             : 
    1044           0 :         XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
    1045             : 
    1046           0 :         XFREE(MTYPE_BGP_PEER, updgrp->conf);
    1047           0 :         XFREE(MTYPE_BGP_UPDGRP, updgrp);
    1048           0 : }
    1049             : 
    1050           0 : static void update_group_add_subgroup(struct update_group *updgrp,
    1051             :                                       struct update_subgroup *subgrp)
    1052             : {
    1053           0 :         if (!updgrp || !subgrp)
    1054             :                 return;
    1055             : 
    1056           0 :         LIST_INSERT_HEAD(&(updgrp->subgrps), subgrp, updgrp_train);
    1057           0 :         subgrp->update_group = updgrp;
    1058             : }
    1059             : 
    1060           0 : static void update_group_remove_subgroup(struct update_group *updgrp,
    1061             :                                          struct update_subgroup *subgrp)
    1062             : {
    1063           0 :         if (!updgrp || !subgrp)
    1064             :                 return;
    1065             : 
    1066           0 :         LIST_REMOVE(subgrp, updgrp_train);
    1067           0 :         subgrp->update_group = NULL;
    1068           0 :         if (LIST_EMPTY(&(updgrp->subgrps)))
    1069           0 :                 update_group_delete(updgrp);
    1070             : }
    1071             : 
    1072             : static struct update_subgroup *
    1073           0 : update_subgroup_create(struct update_group *updgrp)
    1074             : {
    1075           0 :         struct update_subgroup *subgrp;
    1076             : 
    1077           0 :         subgrp = XCALLOC(MTYPE_BGP_UPD_SUBGRP, sizeof(struct update_subgroup));
    1078           0 :         update_subgroup_checkin(subgrp, updgrp);
    1079           0 :         subgrp->v_coalesce = (UPDGRP_INST(updgrp))->coalesce_time;
    1080           0 :         sync_init(subgrp, updgrp);
    1081           0 :         bpacket_queue_init(SUBGRP_PKTQ(subgrp));
    1082           0 :         bpacket_queue_add(SUBGRP_PKTQ(subgrp), NULL, NULL);
    1083           0 :         TAILQ_INIT(&(subgrp->adjq));
    1084           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1085           0 :                 zlog_debug("create subgroup u%" PRIu64 ":s%" PRIu64, updgrp->id,
    1086             :                            subgrp->id);
    1087             : 
    1088           0 :         update_group_add_subgroup(updgrp, subgrp);
    1089             : 
    1090           0 :         UPDGRP_INCR_STAT(updgrp, subgrps_created);
    1091             : 
    1092           0 :         return subgrp;
    1093             : }
    1094             : 
    1095           0 : static void update_subgroup_delete(struct update_subgroup *subgrp)
    1096             : {
    1097           0 :         if (!subgrp)
    1098             :                 return;
    1099             : 
    1100           0 :         if (subgrp->update_group)
    1101           0 :                 UPDGRP_INCR_STAT(subgrp->update_group, subgrps_deleted);
    1102             : 
    1103           0 :         THREAD_OFF(subgrp->t_merge_check);
    1104           0 :         THREAD_OFF(subgrp->t_coalesce);
    1105             : 
    1106           0 :         bpacket_queue_cleanup(SUBGRP_PKTQ(subgrp));
    1107           0 :         subgroup_clear_table(subgrp);
    1108             : 
    1109           0 :         sync_delete(subgrp);
    1110             : 
    1111           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS) && subgrp->update_group)
    1112           0 :                 zlog_debug("delete subgroup u%" PRIu64 ":s%" PRIu64,
    1113             :                            subgrp->update_group->id, subgrp->id);
    1114             : 
    1115           0 :         update_group_remove_subgroup(subgrp->update_group, subgrp);
    1116             : 
    1117           0 :         XFREE(MTYPE_BGP_UPD_SUBGRP, subgrp);
    1118             : }
    1119             : 
    1120           0 : void update_subgroup_inherit_info(struct update_subgroup *to,
    1121             :                                   struct update_subgroup *from)
    1122             : {
    1123           0 :         if (!to || !from)
    1124             :                 return;
    1125             : 
    1126           0 :         to->sflags = from->sflags;
    1127             : }
    1128             : 
    1129             : /*
    1130             :  * update_subgroup_check_delete
    1131             :  *
    1132             :  * Delete a subgroup if it is ready to be deleted.
    1133             :  *
    1134             :  * Returns true if the subgroup was deleted.
    1135             :  */
    1136           0 : static bool update_subgroup_check_delete(struct update_subgroup *subgrp)
    1137             : {
    1138           0 :         if (!subgrp)
    1139             :                 return false;
    1140             : 
    1141           0 :         if (!LIST_EMPTY(&(subgrp->peers)))
    1142             :                 return false;
    1143             : 
    1144           0 :         update_subgroup_delete(subgrp);
    1145             : 
    1146           0 :         return true;
    1147             : }
    1148             : 
    1149             : /*
    1150             :  * update_subgroup_add_peer
    1151             :  *
    1152             :  * @param send_enqueued_packets If true all currently enqueued packets will
    1153             :  *                              also be sent to the peer.
    1154             :  */
    1155           0 : static void update_subgroup_add_peer(struct update_subgroup *subgrp,
    1156             :                                      struct peer_af *paf,
    1157             :                                      int send_enqueued_pkts)
    1158             : {
    1159           0 :         struct bpacket *pkt;
    1160             : 
    1161           0 :         if (!subgrp || !paf)
    1162             :                 return;
    1163             : 
    1164           0 :         LIST_INSERT_HEAD(&(subgrp->peers), paf, subgrp_train);
    1165           0 :         paf->subgroup = subgrp;
    1166           0 :         subgrp->peer_count++;
    1167             : 
    1168           0 :         if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
    1169           0 :                 UPDGRP_PEER_DBG_EN(subgrp->update_group);
    1170             :         }
    1171             : 
    1172           0 :         SUBGRP_INCR_STAT(subgrp, join_events);
    1173             : 
    1174           0 :         if (send_enqueued_pkts) {
    1175           0 :                 pkt = bpacket_queue_first(SUBGRP_PKTQ(subgrp));
    1176             :         } else {
    1177             : 
    1178             :                 /*
    1179             :                  * Hang the peer off of the last, placeholder, packet in the
    1180             :                  * queue. This means it won't see any of the packets that are
    1181             :                  * currently the queue.
    1182             :                  */
    1183           0 :                 pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
    1184           0 :                 assert(pkt->buffer == NULL);
    1185             :         }
    1186             : 
    1187           0 :         bpacket_add_peer(pkt, paf);
    1188             : 
    1189           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1190           0 :                 zlog_debug("peer %s added to subgroup s%" PRIu64,
    1191             :                                 paf->peer->host, subgrp->id);
    1192             : }
    1193             : 
    1194             : /*
    1195             :  * update_subgroup_remove_peer_internal
    1196             :  *
    1197             :  * Internal function that removes a peer from a subgroup, but does not
    1198             :  * delete the subgroup. A call to this function must almost always be
    1199             :  * followed by a call to update_subgroup_check_delete().
    1200             :  *
    1201             :  * @see update_subgroup_remove_peer
    1202             :  */
    1203           0 : static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp,
    1204             :                                                  struct peer_af *paf)
    1205             : {
    1206           0 :         assert(subgrp && paf && subgrp->update_group);
    1207             : 
    1208           0 :         if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
    1209           0 :                 UPDGRP_PEER_DBG_DIS(subgrp->update_group);
    1210             :         }
    1211             : 
    1212           0 :         bpacket_queue_remove_peer(paf);
    1213           0 :         LIST_REMOVE(paf, subgrp_train);
    1214           0 :         paf->subgroup = NULL;
    1215           0 :         subgrp->peer_count--;
    1216             : 
    1217           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1218           0 :                 zlog_debug("peer %s deleted from subgroup s%"
    1219             :                            PRIu64 " peer cnt %d",
    1220             :                            paf->peer->host, subgrp->id, subgrp->peer_count);
    1221           0 :         SUBGRP_INCR_STAT(subgrp, prune_events);
    1222           0 : }
    1223             : 
    1224             : /*
    1225             :  * update_subgroup_remove_peer
    1226             :  */
    1227           3 : void update_subgroup_remove_peer(struct update_subgroup *subgrp,
    1228             :                                  struct peer_af *paf)
    1229             : {
    1230           3 :         if (!subgrp || !paf)
    1231             :                 return;
    1232             : 
    1233           0 :         update_subgroup_remove_peer_internal(subgrp, paf);
    1234             : 
    1235           0 :         if (update_subgroup_check_delete(subgrp))
    1236             :                 return;
    1237             : 
    1238             :         /*
    1239             :          * The deletion of the peer may have caused some packets to be
    1240             :          * deleted from the subgroup packet queue. Check if the subgroup can
    1241             :          * be merged now.
    1242             :          */
    1243           0 :         update_subgroup_check_merge(subgrp, "removed peer from subgroup");
    1244             : }
    1245             : 
    1246           0 : static struct update_subgroup *update_subgroup_find(struct update_group *updgrp,
    1247             :                                                     struct peer_af *paf)
    1248             : {
    1249           0 :         struct update_subgroup *subgrp = NULL;
    1250           0 :         uint64_t version;
    1251             : 
    1252           0 :         if (paf->subgroup) {
    1253           0 :                 assert(0);
    1254             :                 return NULL;
    1255             :         } else
    1256           0 :                 version = 0;
    1257             : 
    1258           0 :         if (!peer_established(PAF_PEER(paf)))
    1259             :                 return NULL;
    1260             : 
    1261           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
    1262           0 :                 if (subgrp->version != version
    1263           0 :                     || CHECK_FLAG(subgrp->sflags,
    1264             :                                   SUBGRP_STATUS_DEFAULT_ORIGINATE))
    1265           0 :                         continue;
    1266             : 
    1267             :                 /*
    1268             :                  * The version number is not meaningful on a subgroup that needs
    1269             :                  * a refresh.
    1270             :                  */
    1271           0 :                 if (update_subgroup_needs_refresh(subgrp))
    1272           0 :                         continue;
    1273             : 
    1274             :                 break;
    1275             :         }
    1276             : 
    1277             :         return subgrp;
    1278             : }
    1279             : 
    1280             : /*
    1281             :  * update_subgroup_ready_for_merge
    1282             :  *
    1283             :  * Returns true if this subgroup is in a state that allows it to be
    1284             :  * merged into another subgroup.
    1285             :  */
    1286           0 : static bool update_subgroup_ready_for_merge(struct update_subgroup *subgrp)
    1287             : {
    1288             : 
    1289             :         /*
    1290             :          * Not ready if there are any encoded packets waiting to be written
    1291             :          * out to peers.
    1292             :          */
    1293           0 :         if (!bpacket_queue_is_empty(SUBGRP_PKTQ(subgrp)))
    1294             :                 return false;
    1295             : 
    1296             :         /*
    1297             :          * Not ready if there enqueued updates waiting to be encoded.
    1298             :          */
    1299           0 :         if (!advertise_list_is_empty(subgrp))
    1300             :                 return false;
    1301             : 
    1302             :         /*
    1303             :          * Don't attempt to merge a subgroup that needs a refresh. For one,
    1304             :          * we can't determine if the adj_out of such a group matches that of
    1305             :          * another group.
    1306             :          */
    1307           0 :         if (update_subgroup_needs_refresh(subgrp))
    1308           0 :                 return false;
    1309             : 
    1310             :         return true;
    1311             : }
    1312             : 
    1313             : /*
    1314             :  * update_subgrp_can_merge_into
    1315             :  *
    1316             :  * Returns true if the first subgroup can merge into the second
    1317             :  * subgroup.
    1318             :  */
    1319           0 : static int update_subgroup_can_merge_into(struct update_subgroup *subgrp,
    1320             :                                           struct update_subgroup *target)
    1321             : {
    1322             : 
    1323           0 :         if (subgrp == target)
    1324             :                 return 0;
    1325             : 
    1326             :         /*
    1327             :          * Both must have processed the BRIB to the same point in order to
    1328             :          * be merged.
    1329             :          */
    1330           0 :         if (subgrp->version != target->version)
    1331             :                 return 0;
    1332             : 
    1333           0 :         if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)
    1334           0 :             != CHECK_FLAG(target->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
    1335             :                 return 0;
    1336             : 
    1337           0 :         if (subgrp->adj_count != target->adj_count)
    1338             :                 return 0;
    1339             : 
    1340           0 :         return update_subgroup_ready_for_merge(target);
    1341             : }
    1342             : 
    1343             : /*
    1344             :  * update_subgroup_merge
    1345             :  *
    1346             :  * Merge the first subgroup into the second one.
    1347             :  */
    1348           0 : static void update_subgroup_merge(struct update_subgroup *subgrp,
    1349             :                                   struct update_subgroup *target,
    1350             :                                   const char *reason)
    1351             : {
    1352           0 :         struct peer_af *paf;
    1353           0 :         int result;
    1354           0 :         int peer_count;
    1355             : 
    1356           0 :         assert(subgrp->adj_count == target->adj_count);
    1357             : 
    1358           0 :         peer_count = subgrp->peer_count;
    1359             : 
    1360           0 :         while (1) {
    1361           0 :                 paf = LIST_FIRST(&subgrp->peers);
    1362           0 :                 if (!paf)
    1363             :                         break;
    1364             : 
    1365           0 :                 update_subgroup_remove_peer_internal(subgrp, paf);
    1366             : 
    1367             :                 /*
    1368             :                  * Add the peer to the target subgroup, while making sure that
    1369             :                  * any currently enqueued packets won't be sent to it. Enqueued
    1370             :                  * packets could, for example, result in an unnecessary withdraw
    1371             :                  * followed by an advertise.
    1372             :                  */
    1373           0 :                 update_subgroup_add_peer(target, paf, 0);
    1374             :         }
    1375             : 
    1376           0 :         SUBGRP_INCR_STAT(target, merge_events);
    1377             : 
    1378           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1379           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64" (%d peers) merged into u%" PRIu64 ":s%" PRIu64", trigger: %s",
    1380             :                            subgrp->update_group->id, subgrp->id, peer_count,
    1381             :                            target->update_group->id, target->id,
    1382             :                            reason ? reason : "unknown");
    1383             : 
    1384           0 :         result = update_subgroup_check_delete(subgrp);
    1385           0 :         assert(result);
    1386           0 : }
    1387             : 
    1388             : /*
    1389             :  * update_subgroup_check_merge
    1390             :  *
    1391             :  * Merge this subgroup into another subgroup if possible.
    1392             :  *
    1393             :  * Returns true if the subgroup has been merged. The subgroup pointer
    1394             :  * should not be accessed in this case.
    1395             :  */
    1396           0 : bool update_subgroup_check_merge(struct update_subgroup *subgrp,
    1397             :                                  const char *reason)
    1398             : {
    1399           0 :         struct update_subgroup *target;
    1400             : 
    1401           0 :         if (!update_subgroup_ready_for_merge(subgrp))
    1402             :                 return false;
    1403             : 
    1404             :         /*
    1405             :          * Look for a subgroup to merge into.
    1406             :          */
    1407           0 :         UPDGRP_FOREACH_SUBGRP (subgrp->update_group, target) {
    1408           0 :                 if (update_subgroup_can_merge_into(subgrp, target))
    1409             :                         break;
    1410             :         }
    1411             : 
    1412           0 :         if (!target)
    1413             :                 return false;
    1414             : 
    1415           0 :         update_subgroup_merge(subgrp, target, reason);
    1416           0 :         return true;
    1417             : }
    1418             : 
    1419             : /*
    1420             : * update_subgroup_merge_check_thread_cb
    1421             : */
    1422           0 : static void update_subgroup_merge_check_thread_cb(struct thread *thread)
    1423             : {
    1424           0 :         struct update_subgroup *subgrp;
    1425             : 
    1426           0 :         subgrp = THREAD_ARG(thread);
    1427             : 
    1428           0 :         subgrp->t_merge_check = NULL;
    1429             : 
    1430           0 :         update_subgroup_check_merge(subgrp, "triggered merge check");
    1431           0 : }
    1432             : 
    1433             : /*
    1434             :  * update_subgroup_trigger_merge_check
    1435             :  *
    1436             :  * Triggers a call to update_subgroup_check_merge() on a clean context.
    1437             :  *
    1438             :  * @param force If true, the merge check will be triggered even if the
    1439             :  *              subgroup doesn't currently look ready for a merge.
    1440             :  *
    1441             :  * Returns true if a merge check will be performed shortly.
    1442             :  */
    1443           0 : bool update_subgroup_trigger_merge_check(struct update_subgroup *subgrp,
    1444             :                                          int force)
    1445             : {
    1446           0 :         if (subgrp->t_merge_check)
    1447             :                 return true;
    1448             : 
    1449           0 :         if (!force && !update_subgroup_ready_for_merge(subgrp))
    1450             :                 return false;
    1451             : 
    1452           0 :         subgrp->t_merge_check = NULL;
    1453           0 :         thread_add_timer_msec(bm->master, update_subgroup_merge_check_thread_cb,
    1454             :                               subgrp, 0, &subgrp->t_merge_check);
    1455             : 
    1456           0 :         SUBGRP_INCR_STAT(subgrp, merge_checks_triggered);
    1457             : 
    1458             :         return true;
    1459             : }
    1460             : 
    1461             : /*
    1462             :  * update_subgroup_copy_adj_out
    1463             :  *
    1464             :  * Helper function that clones the adj out (state about advertised
    1465             :  * routes) from one subgroup to another. It assumes that the adj out
    1466             :  * of the target subgroup is empty.
    1467             :  */
    1468           0 : static void update_subgroup_copy_adj_out(struct update_subgroup *source,
    1469             :                                          struct update_subgroup *dest)
    1470             : {
    1471           0 :         struct bgp_adj_out *aout, *aout_copy;
    1472             : 
    1473           0 :         SUBGRP_FOREACH_ADJ (source, aout) {
    1474             :                 /*
    1475             :                  * Copy the adj out.
    1476             :                  */
    1477           0 :                 aout_copy = bgp_adj_out_alloc(dest, aout->dest,
    1478             :                                               aout->addpath_tx_id);
    1479           0 :                 aout_copy->attr =
    1480           0 :                         aout->attr ? bgp_attr_intern(aout->attr) : NULL;
    1481             :         }
    1482             : 
    1483           0 :         dest->scount = source->scount;
    1484           0 : }
    1485             : 
    1486             : /*
    1487             :  * update_subgroup_copy_packets
    1488             :  *
    1489             :  * Copy packets after and including the given packet to the subgroup
    1490             :  *  'dest'.
    1491             :  *
    1492             :  * Returns the number of packets copied.
    1493             :  */
    1494           0 : static int update_subgroup_copy_packets(struct update_subgroup *dest,
    1495             :                                         struct bpacket *pkt)
    1496             : {
    1497           0 :         int count;
    1498             : 
    1499           0 :         count = 0;
    1500           0 :         while (pkt && pkt->buffer) {
    1501           0 :                 bpacket_queue_add(SUBGRP_PKTQ(dest), stream_dup(pkt->buffer),
    1502           0 :                                   &pkt->arr);
    1503           0 :                 count++;
    1504           0 :                 pkt = bpacket_next(pkt);
    1505             :         }
    1506             : 
    1507           0 :         return count;
    1508             : }
    1509             : 
    1510           0 : static bool updgrp_prefix_list_update(struct update_group *updgrp,
    1511             :                                       const char *name)
    1512             : {
    1513           0 :         struct peer *peer;
    1514           0 :         struct bgp_filter *filter;
    1515             : 
    1516           0 :         peer = UPDGRP_PEER(updgrp);
    1517           0 :         filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
    1518             : 
    1519           0 :         if (PREFIX_LIST_OUT_NAME(filter)
    1520           0 :             && (strcmp(name, PREFIX_LIST_OUT_NAME(filter)) == 0)) {
    1521           0 :                 PREFIX_LIST_OUT(filter) = prefix_list_lookup(
    1522             :                         UPDGRP_AFI(updgrp), PREFIX_LIST_OUT_NAME(filter));
    1523           0 :                 return true;
    1524             :         }
    1525             :         return false;
    1526             : }
    1527             : 
    1528           0 : static bool updgrp_filter_list_update(struct update_group *updgrp,
    1529             :                                       const char *name)
    1530             : {
    1531           0 :         struct peer *peer;
    1532           0 :         struct bgp_filter *filter;
    1533             : 
    1534           0 :         peer = UPDGRP_PEER(updgrp);
    1535           0 :         filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
    1536             : 
    1537           0 :         if (FILTER_LIST_OUT_NAME(filter)
    1538           0 :             && (strcmp(name, FILTER_LIST_OUT_NAME(filter)) == 0)) {
    1539           0 :                 FILTER_LIST_OUT(filter) =
    1540           0 :                         as_list_lookup(FILTER_LIST_OUT_NAME(filter));
    1541           0 :                 return true;
    1542             :         }
    1543             :         return false;
    1544             : }
    1545             : 
    1546           0 : static bool updgrp_distribute_list_update(struct update_group *updgrp,
    1547             :                                           const char *name)
    1548             : {
    1549           0 :         struct peer *peer;
    1550           0 :         struct bgp_filter *filter;
    1551             : 
    1552           0 :         peer = UPDGRP_PEER(updgrp);
    1553           0 :         filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
    1554             : 
    1555           0 :         if (DISTRIBUTE_OUT_NAME(filter)
    1556           0 :             && (strcmp(name, DISTRIBUTE_OUT_NAME(filter)) == 0)) {
    1557           0 :                 DISTRIBUTE_OUT(filter) = access_list_lookup(
    1558             :                         UPDGRP_AFI(updgrp), DISTRIBUTE_OUT_NAME(filter));
    1559           0 :                 return true;
    1560             :         }
    1561             :         return false;
    1562             : }
    1563             : 
    1564           0 : static int updgrp_route_map_update(struct update_group *updgrp,
    1565             :                                    const char *name, int *def_rmap_changed)
    1566             : {
    1567           0 :         struct peer *peer;
    1568           0 :         struct bgp_filter *filter;
    1569           0 :         int changed = 0;
    1570           0 :         afi_t afi;
    1571           0 :         safi_t safi;
    1572             : 
    1573           0 :         peer = UPDGRP_PEER(updgrp);
    1574           0 :         afi = UPDGRP_AFI(updgrp);
    1575           0 :         safi = UPDGRP_SAFI(updgrp);
    1576           0 :         filter = &peer->filter[afi][safi];
    1577             : 
    1578           0 :         if (ROUTE_MAP_OUT_NAME(filter)
    1579           0 :             && (strcmp(name, ROUTE_MAP_OUT_NAME(filter)) == 0)) {
    1580           0 :                 ROUTE_MAP_OUT(filter) = route_map_lookup_by_name(name);
    1581             : 
    1582           0 :                 changed = 1;
    1583             :         }
    1584             : 
    1585           0 :         if (UNSUPPRESS_MAP_NAME(filter)
    1586           0 :             && (strcmp(name, UNSUPPRESS_MAP_NAME(filter)) == 0)) {
    1587           0 :                 UNSUPPRESS_MAP(filter) = route_map_lookup_by_name(name);
    1588           0 :                 changed = 1;
    1589             :         }
    1590             : 
    1591             :         /* process default-originate route-map */
    1592           0 :         if (peer->default_rmap[afi][safi].name
    1593           0 :             && (strcmp(name, peer->default_rmap[afi][safi].name) == 0)) {
    1594           0 :                 peer->default_rmap[afi][safi].map =
    1595           0 :                         route_map_lookup_by_name(name);
    1596           0 :                 if (def_rmap_changed)
    1597           0 :                         *def_rmap_changed = 1;
    1598             :         }
    1599           0 :         return changed;
    1600             : }
    1601             : 
    1602             : /*
    1603             :  * hash iteration callback function to process a policy change for an
    1604             :  * update group. Check if the changed policy matches the updgrp's
    1605             :  * outbound route-map or unsuppress-map or default-originate map or
    1606             :  * filter-list or prefix-list or distribute-list.
    1607             :  * Trigger update generation accordingly.
    1608             :  */
    1609           0 : static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
    1610             : {
    1611           0 :         struct updwalk_context *ctx = arg;
    1612           0 :         struct update_subgroup *subgrp;
    1613           0 :         int changed = 0;
    1614           0 :         int def_changed = 0;
    1615             : 
    1616           0 :         if (!updgrp || !ctx || !ctx->policy_name)
    1617             :                 return UPDWALK_CONTINUE;
    1618             : 
    1619           0 :         switch (ctx->policy_type) {
    1620           0 :         case BGP_POLICY_ROUTE_MAP:
    1621           0 :                 changed = updgrp_route_map_update(updgrp, ctx->policy_name,
    1622             :                                                   &def_changed);
    1623           0 :                 break;
    1624           0 :         case BGP_POLICY_FILTER_LIST:
    1625           0 :                 changed = updgrp_filter_list_update(updgrp, ctx->policy_name);
    1626           0 :                 break;
    1627           0 :         case BGP_POLICY_PREFIX_LIST:
    1628           0 :                 changed = updgrp_prefix_list_update(updgrp, ctx->policy_name);
    1629           0 :                 break;
    1630           0 :         case BGP_POLICY_DISTRIBUTE_LIST:
    1631           0 :                 changed =
    1632           0 :                         updgrp_distribute_list_update(updgrp, ctx->policy_name);
    1633           0 :                 break;
    1634             :         default:
    1635             :                 break;
    1636             :         }
    1637             : 
    1638             :         /* If not doing route update, return after updating "config" */
    1639           0 :         if (!ctx->policy_route_update)
    1640             :                 return UPDWALK_CONTINUE;
    1641             : 
    1642             :         /* If nothing has changed, return after updating "config" */
    1643           0 :         if (!changed && !def_changed)
    1644             :                 return UPDWALK_CONTINUE;
    1645             : 
    1646             :         /*
    1647             :          * If something has changed, at the beginning of a route-map
    1648             :          * modification
    1649             :          * event, mark each subgroup's needs-refresh bit. For one, it signals to
    1650             :          * whoever that the subgroup needs a refresh. Second, it prevents
    1651             :          * premature
    1652             :          * merge of this subgroup with another before a complete (outbound)
    1653             :          * refresh.
    1654             :          */
    1655           0 :         if (ctx->policy_event_start_flag) {
    1656           0 :                 UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
    1657           0 :                         update_subgroup_set_needs_refresh(subgrp, 1);
    1658             :                 }
    1659             :                 return UPDWALK_CONTINUE;
    1660             :         }
    1661             : 
    1662           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
    1663             :                 /* Avoid supressing duplicate routes later
    1664             :                  * when processing in subgroup_announce_table().
    1665             :                  */
    1666           0 :                 SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
    1667             : 
    1668           0 :                 if (changed) {
    1669           0 :                         if (bgp_debug_update(NULL, NULL, updgrp, 0))
    1670           0 :                                 zlog_debug(
    1671             :                                         "u%" PRIu64 ":s%" PRIu64" announcing routes upon policy %s (type %d) change",
    1672             :                                         updgrp->id, subgrp->id,
    1673             :                                         ctx->policy_name, ctx->policy_type);
    1674           0 :                         subgroup_announce_route(subgrp);
    1675             :                 }
    1676           0 :                 if (def_changed) {
    1677           0 :                         if (bgp_debug_update(NULL, NULL, updgrp, 0))
    1678           0 :                                 zlog_debug(
    1679             :                                         "u%" PRIu64 ":s%" PRIu64" announcing default upon default routemap %s change",
    1680             :                                         updgrp->id, subgrp->id,
    1681             :                                         ctx->policy_name);
    1682           0 :                         if (route_map_lookup_by_name(ctx->policy_name)) {
    1683             :                                 /*
    1684             :                                  * When there is change in routemap, this flow
    1685             :                                  * is triggered. the routemap is still present
    1686             :                                  * in lib, hence its a update flow. The flag
    1687             :                                  * needs to be unset.
    1688             :                                  */
    1689           0 :                                 UNSET_FLAG(subgrp->sflags,
    1690             :                                            SUBGRP_STATUS_DEFAULT_ORIGINATE);
    1691           0 :                                 subgroup_default_originate(subgrp, 0);
    1692             :                         } else {
    1693             :                                 /*
    1694             :                                  * This is a explicit withdraw, since the
    1695             :                                  * routemap is not present in routemap lib. need
    1696             :                                  * to pass 1 for withdraw arg.
    1697             :                                  */
    1698           0 :                                 subgroup_default_originate(subgrp, 1);
    1699             :                         }
    1700             :                 }
    1701           0 :                 update_subgroup_set_needs_refresh(subgrp, 0);
    1702             :         }
    1703             :         return UPDWALK_CONTINUE;
    1704             : }
    1705             : 
    1706           0 : static int update_group_walkcb(struct hash_bucket *bucket, void *arg)
    1707             : {
    1708           0 :         struct update_group *updgrp = bucket->data;
    1709           0 :         struct updwalk_context *wctx = arg;
    1710           0 :         int ret = (*wctx->cb)(updgrp, wctx->context);
    1711           0 :         return ret;
    1712             : }
    1713             : 
    1714           0 : static int update_group_periodic_merge_walkcb(struct update_group *updgrp,
    1715             :                                               void *arg)
    1716             : {
    1717           0 :         struct update_subgroup *subgrp;
    1718           0 :         struct update_subgroup *tmp_subgrp;
    1719           0 :         const char *reason = arg;
    1720             : 
    1721           0 :         UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp)
    1722           0 :                 update_subgroup_check_merge(subgrp, reason);
    1723           0 :         return UPDWALK_CONTINUE;
    1724             : }
    1725             : 
    1726             : /********************
    1727             :  * PUBLIC FUNCTIONS
    1728             :  ********************/
    1729             : 
    1730             : /*
    1731             :  * trigger function when a policy (route-map/filter-list/prefix-list/
    1732             :  * distribute-list etc.) content changes. Go through all the
    1733             :  * update groups and process the change.
    1734             :  *
    1735             :  * bgp: the bgp instance
    1736             :  * ptype: the type of policy that got modified, see bgpd.h
    1737             :  * pname: name of the policy
    1738             :  * route_update: flag to control if an automatic update generation should
    1739             :  *                occur
    1740             :  * start_event: flag that indicates if it's the beginning of the change.
    1741             :  *             Esp. when the user is changing the content interactively
    1742             :  *             over multiple statements. Useful to set dirty flag on
    1743             :  *             update groups.
    1744             :  */
    1745           0 : void update_group_policy_update(struct bgp *bgp, enum bgp_policy_type ptype,
    1746             :                                 const char *pname, bool route_update,
    1747             :                                 int start_event)
    1748             : {
    1749           0 :         struct updwalk_context ctx;
    1750             : 
    1751           0 :         memset(&ctx, 0, sizeof(ctx));
    1752           0 :         ctx.policy_type = ptype;
    1753           0 :         ctx.policy_name = pname;
    1754           0 :         ctx.policy_route_update = route_update;
    1755           0 :         ctx.policy_event_start_flag = start_event;
    1756           0 :         ctx.flags = 0;
    1757             : 
    1758           0 :         update_group_walk(bgp, updgrp_policy_update_walkcb, &ctx);
    1759           0 : }
    1760             : 
    1761             : /*
    1762             :  * update_subgroup_split_peer
    1763             :  *
    1764             :  * Ensure that the given peer is in a subgroup of its own in the
    1765             :  * specified update group.
    1766             :  */
    1767           0 : void update_subgroup_split_peer(struct peer_af *paf,
    1768             :                                 struct update_group *updgrp)
    1769             : {
    1770           0 :         struct update_subgroup *old_subgrp, *subgrp;
    1771           0 :         uint64_t old_id;
    1772             : 
    1773             : 
    1774           0 :         old_subgrp = paf->subgroup;
    1775             : 
    1776           0 :         if (!updgrp)
    1777           0 :                 updgrp = old_subgrp->update_group;
    1778             : 
    1779             :         /*
    1780             :          * If the peer is alone in its subgroup, reuse the existing
    1781             :          * subgroup.
    1782             :          */
    1783           0 :         if (old_subgrp->peer_count == 1) {
    1784           0 :                 if (updgrp == old_subgrp->update_group)
    1785             :                         return;
    1786             : 
    1787           0 :                 subgrp = old_subgrp;
    1788           0 :                 old_id = old_subgrp->update_group->id;
    1789             : 
    1790           0 :                 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
    1791           0 :                         UPDGRP_PEER_DBG_DIS(old_subgrp->update_group);
    1792             :                 }
    1793             : 
    1794           0 :                 update_group_remove_subgroup(old_subgrp->update_group,
    1795             :                                              old_subgrp);
    1796           0 :                 update_group_add_subgroup(updgrp, subgrp);
    1797             : 
    1798           0 :                 if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
    1799           0 :                         UPDGRP_PEER_DBG_EN(updgrp);
    1800             :                 }
    1801           0 :                 if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1802           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s moved to u%" PRIu64 ":s%" PRIu64,
    1803             :                                    old_id, subgrp->id, paf->peer->host,
    1804             :                                    updgrp->id, subgrp->id);
    1805             : 
    1806             :                 /*
    1807             :                  * The state of the subgroup (adj_out, advs, packet queue etc)
    1808             :                  * is consistent internally, but may not be identical to other
    1809             :                  * subgroups in the new update group even if the version number
    1810             :                  * matches up. Make sure a full refresh is done before the
    1811             :                  * subgroup is merged with another.
    1812             :                  */
    1813           0 :                 update_subgroup_set_needs_refresh(subgrp, 1);
    1814             : 
    1815           0 :                 SUBGRP_INCR_STAT(subgrp, updgrp_switch_events);
    1816           0 :                 return;
    1817             :         }
    1818             : 
    1819             :         /*
    1820             :          * Create a new subgroup under the specified update group, and copy
    1821             :          * over relevant state to it.
    1822             :          */
    1823           0 :         subgrp = update_subgroup_create(updgrp);
    1824           0 :         update_subgroup_inherit_info(subgrp, old_subgrp);
    1825             : 
    1826           0 :         subgrp->split_from.update_group_id = old_subgrp->update_group->id;
    1827           0 :         subgrp->split_from.subgroup_id = old_subgrp->id;
    1828             : 
    1829             :         /*
    1830             :          * Copy out relevant state from the old subgroup.
    1831             :          */
    1832           0 :         update_subgroup_copy_adj_out(paf->subgroup, subgrp);
    1833           0 :         update_subgroup_copy_packets(subgrp, paf->next_pkt_to_send);
    1834             : 
    1835           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    1836           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s split and moved into u%" PRIu64":s%" PRIu64,
    1837             :                            paf->subgroup->update_group->id, paf->subgroup->id,
    1838             :                            paf->peer->host, updgrp->id, subgrp->id);
    1839             : 
    1840           0 :         SUBGRP_INCR_STAT(paf->subgroup, split_events);
    1841             : 
    1842             :         /*
    1843             :          * Since queued advs were left behind, this new subgroup needs a
    1844             :          * refresh.
    1845             :          */
    1846           0 :         update_subgroup_set_needs_refresh(subgrp, 1);
    1847             : 
    1848             :         /*
    1849             :          * Remove peer from old subgroup, and add it to the new one.
    1850             :          */
    1851           0 :         update_subgroup_remove_peer(paf->subgroup, paf);
    1852             : 
    1853           0 :         update_subgroup_add_peer(subgrp, paf, 1);
    1854             : }
    1855             : 
    1856           2 : void update_bgp_group_init(struct bgp *bgp)
    1857             : {
    1858           2 :         int afid;
    1859             : 
    1860          28 :         AF_FOREACH (afid)
    1861          26 :                 bgp->update_groups[afid] =
    1862          26 :                         hash_create(updgrp_hash_key_make, updgrp_hash_cmp,
    1863             :                                     "BGP Update Group Hash");
    1864           2 : }
    1865             : 
    1866           2 : void update_bgp_group_free(struct bgp *bgp)
    1867             : {
    1868           2 :         int afid;
    1869             : 
    1870          28 :         AF_FOREACH (afid) {
    1871          26 :                 if (bgp->update_groups[afid]) {
    1872          26 :                         hash_free(bgp->update_groups[afid]);
    1873          26 :                         bgp->update_groups[afid] = NULL;
    1874             :                 }
    1875             :         }
    1876           2 : }
    1877             : 
    1878           0 : void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
    1879             :                        uint64_t subgrp_id, bool uj)
    1880             : {
    1881           0 :         struct updwalk_context ctx;
    1882           0 :         json_object *json_vrf_obj = NULL;
    1883             : 
    1884           0 :         memset(&ctx, 0, sizeof(ctx));
    1885           0 :         ctx.vty = vty;
    1886           0 :         ctx.subgrp_id = subgrp_id;
    1887           0 :         ctx.uj = uj;
    1888             : 
    1889           0 :         if (uj) {
    1890           0 :                 ctx.json_updategrps = json_object_new_object();
    1891           0 :                 json_vrf_obj = json_object_new_object();
    1892             :         }
    1893             : 
    1894           0 :         update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
    1895             : 
    1896           0 :         if (uj) {
    1897           0 :                 const char *vname;
    1898             : 
    1899           0 :                 if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
    1900           0 :                         vname = VRF_DEFAULT_NAME;
    1901             :                 else
    1902           0 :                         vname = bgp->name;
    1903           0 :                 json_object_object_add(json_vrf_obj, vname,
    1904           0 :                                        ctx.json_updategrps);
    1905           0 :                 vty_json(vty, json_vrf_obj);
    1906             :         }
    1907           0 : }
    1908             : 
    1909             : /*
    1910             :  * update_group_show_stats
    1911             :  *
    1912             :  * Show global statistics about update groups.
    1913             :  */
    1914           0 : void update_group_show_stats(struct bgp *bgp, struct vty *vty)
    1915             : {
    1916           0 :         vty_out(vty, "Update groups created: %u\n",
    1917             :                 bgp->update_group_stats.updgrps_created);
    1918           0 :         vty_out(vty, "Update groups deleted: %u\n",
    1919             :                 bgp->update_group_stats.updgrps_deleted);
    1920           0 :         vty_out(vty, "Update subgroups created: %u\n",
    1921             :                 bgp->update_group_stats.subgrps_created);
    1922           0 :         vty_out(vty, "Update subgroups deleted: %u\n",
    1923             :                 bgp->update_group_stats.subgrps_deleted);
    1924           0 :         vty_out(vty, "Join events: %u\n", bgp->update_group_stats.join_events);
    1925           0 :         vty_out(vty, "Prune events: %u\n",
    1926             :                 bgp->update_group_stats.prune_events);
    1927           0 :         vty_out(vty, "Merge events: %u\n",
    1928             :                 bgp->update_group_stats.merge_events);
    1929           0 :         vty_out(vty, "Split events: %u\n",
    1930             :                 bgp->update_group_stats.split_events);
    1931           0 :         vty_out(vty, "Update group switch events: %u\n",
    1932             :                 bgp->update_group_stats.updgrp_switch_events);
    1933           0 :         vty_out(vty, "Peer route refreshes combined: %u\n",
    1934             :                 bgp->update_group_stats.peer_refreshes_combined);
    1935           0 :         vty_out(vty, "Merge checks triggered: %u\n",
    1936             :                 bgp->update_group_stats.merge_checks_triggered);
    1937           0 : }
    1938             : 
    1939             : /*
    1940             :  * update_group_adjust_peer
    1941             :  */
    1942           0 : void update_group_adjust_peer(struct peer_af *paf)
    1943             : {
    1944           0 :         struct update_group *updgrp;
    1945           0 :         struct update_subgroup *subgrp, *old_subgrp;
    1946           0 :         struct peer *peer;
    1947             : 
    1948           0 :         if (!paf)
    1949             :                 return;
    1950             : 
    1951           0 :         peer = PAF_PEER(paf);
    1952           0 :         if (!peer_established(peer)) {
    1953             :                 return;
    1954             :         }
    1955             : 
    1956           0 :         if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) {
    1957             :                 return;
    1958             :         }
    1959             : 
    1960           0 :         if (!peer->afc_nego[paf->afi][paf->safi]) {
    1961             :                 return;
    1962             :         }
    1963             : 
    1964           0 :         updgrp = update_group_find(paf);
    1965           0 :         if (!updgrp) {
    1966           0 :                 updgrp = update_group_create(paf);
    1967           0 :                 if (!updgrp) {
    1968           0 :                         flog_err(EC_BGP_UPDGRP_CREATE,
    1969             :                                  "couldn't create update group for peer %s",
    1970             :                                  paf->peer->host);
    1971           0 :                         return;
    1972             :                 }
    1973             :         }
    1974             : 
    1975           0 :         old_subgrp = paf->subgroup;
    1976             : 
    1977           0 :         if (old_subgrp) {
    1978             : 
    1979             :                 /*
    1980             :                  * If the update group of the peer is unchanged, the peer can
    1981             :                  * stay
    1982             :                  * in its existing subgroup and we're done.
    1983             :                  */
    1984           0 :                 if (old_subgrp->update_group == updgrp)
    1985             :                         return;
    1986             : 
    1987             :                 /*
    1988             :                  * The peer is switching between update groups. Put it in its
    1989             :                  * own subgroup under the new update group.
    1990             :                  */
    1991           0 :                 update_subgroup_split_peer(paf, updgrp);
    1992           0 :                 return;
    1993             :         }
    1994             : 
    1995           0 :         subgrp = update_subgroup_find(updgrp, paf);
    1996           0 :         if (!subgrp) {
    1997           0 :                 subgrp = update_subgroup_create(updgrp);
    1998           0 :                 if (!subgrp)
    1999             :                         return;
    2000             :         }
    2001             : 
    2002           0 :         update_subgroup_add_peer(subgrp, paf, 1);
    2003           0 :         if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
    2004           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64 " add peer %s", updgrp->id,
    2005             :                            subgrp->id, paf->peer->host);
    2006             : 
    2007             :         return;
    2008             : }
    2009             : 
    2010           0 : int update_group_adjust_soloness(struct peer *peer, int set)
    2011             : {
    2012           0 :         struct peer_group *group;
    2013           0 :         struct listnode *node, *nnode;
    2014             : 
    2015           0 :         if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
    2016           0 :                 peer_lonesoul_or_not(peer, set);
    2017           0 :                 if (peer_established(peer))
    2018           0 :                         bgp_announce_route_all(peer);
    2019             :         } else {
    2020           0 :                 group = peer->group;
    2021           0 :                 for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
    2022           0 :                         peer_lonesoul_or_not(peer, set);
    2023           0 :                         if (peer_established(peer))
    2024           0 :                                 bgp_announce_route_all(peer);
    2025             :                 }
    2026             :         }
    2027           0 :         return 0;
    2028             : }
    2029             : 
    2030             : /*
    2031             :  * update_subgroup_rib
    2032             :  */
    2033           0 : struct bgp_table *update_subgroup_rib(struct update_subgroup *subgrp)
    2034             : {
    2035           0 :         struct bgp *bgp;
    2036             : 
    2037           0 :         bgp = SUBGRP_INST(subgrp);
    2038           0 :         if (!bgp)
    2039             :                 return NULL;
    2040             : 
    2041           0 :         return bgp->rib[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)];
    2042             : }
    2043             : 
    2044           0 : void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
    2045             :                           updgrp_walkcb cb, void *ctx)
    2046             : {
    2047           0 :         struct updwalk_context wctx;
    2048           0 :         int afid;
    2049             : 
    2050           0 :         if (!bgp)
    2051           0 :                 return;
    2052           0 :         afid = afindex(afi, safi);
    2053           0 :         if (afid >= BGP_AF_MAX)
    2054             :                 return;
    2055             : 
    2056           0 :         memset(&wctx, 0, sizeof(wctx));
    2057           0 :         wctx.cb = cb;
    2058           0 :         wctx.context = ctx;
    2059             : 
    2060           0 :         if (bgp->update_groups[afid])
    2061           0 :                 hash_walk(bgp->update_groups[afid], update_group_walkcb, &wctx);
    2062             : }
    2063             : 
    2064           0 : void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx)
    2065             : {
    2066           0 :         afi_t afi;
    2067           0 :         safi_t safi;
    2068             : 
    2069           0 :         FOREACH_AFI_SAFI (afi, safi) {
    2070           0 :                 update_group_af_walk(bgp, afi, safi, cb, ctx);
    2071             :         }
    2072           0 : }
    2073             : 
    2074           0 : void update_group_periodic_merge(struct bgp *bgp)
    2075             : {
    2076           0 :         char reason[] = "periodic merge check";
    2077             : 
    2078           0 :         update_group_walk(bgp, update_group_periodic_merge_walkcb,
    2079             :                           (void *)reason);
    2080           0 : }
    2081             : 
    2082             : static int
    2083           0 : update_group_default_originate_route_map_walkcb(struct update_group *updgrp,
    2084             :                                                 void *arg)
    2085             : {
    2086           0 :         struct update_subgroup *subgrp;
    2087           0 :         struct peer *peer;
    2088           0 :         afi_t afi;
    2089           0 :         safi_t safi;
    2090             : 
    2091           0 :         UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
    2092           0 :                 peer = SUBGRP_PEER(subgrp);
    2093           0 :                 afi = SUBGRP_AFI(subgrp);
    2094           0 :                 safi = SUBGRP_SAFI(subgrp);
    2095             : 
    2096           0 :                 if (peer->default_rmap[afi][safi].name) {
    2097             :                         /*
    2098             :                          * When there is change in routemap this flow will
    2099             :                          * be triggered. We need to unset the Flag to ensure
    2100             :                          * the update flow gets triggered.
    2101             :                          */
    2102           0 :                         UNSET_FLAG(subgrp->sflags,
    2103             :                                    SUBGRP_STATUS_DEFAULT_ORIGINATE);
    2104           0 :                         subgroup_default_originate(subgrp, 0);
    2105             :                 }
    2106             :         }
    2107             : 
    2108           0 :         return UPDWALK_CONTINUE;
    2109             : }
    2110             : 
    2111           0 : void update_group_refresh_default_originate_route_map(struct thread *thread)
    2112             : {
    2113           0 :         struct bgp *bgp;
    2114           0 :         char reason[] = "refresh default-originate route-map";
    2115             : 
    2116           0 :         bgp = THREAD_ARG(thread);
    2117           0 :         update_group_walk(bgp, update_group_default_originate_route_map_walkcb,
    2118             :                           reason);
    2119           0 :         THREAD_OFF(bgp->t_rmap_def_originate_eval);
    2120           0 :         bgp_unlock(bgp);
    2121           0 : }
    2122             : 
    2123             : /*
    2124             :  * peer_af_announce_route
    2125             :  *
    2126             :  * Refreshes routes out to a peer_af immediately.
    2127             :  *
    2128             :  * If the combine parameter is true, then this function will try to
    2129             :  * gather other peers in the subgroup for which a route announcement
    2130             :  * is pending and efficently announce routes to all of them.
    2131             :  *
    2132             :  * For now, the 'combine' option has an effect only if all peers in
    2133             :  * the subgroup have a route announcement pending.
    2134             :  */
    2135           0 : void peer_af_announce_route(struct peer_af *paf, int combine)
    2136             : {
    2137           0 :         struct update_subgroup *subgrp;
    2138           0 :         struct peer_af *cur_paf;
    2139           0 :         int all_pending;
    2140             : 
    2141           0 :         subgrp = paf->subgroup;
    2142           0 :         all_pending = 0;
    2143             : 
    2144           0 :         if (combine) {
    2145             :                 /*
    2146             :                  * If there are other peers in the old subgroup that also need
    2147             :                  * routes to be announced, pull them into the peer's new
    2148             :                  * subgroup.
    2149             :                  * Combine route announcement with other peers if possible.
    2150             :                  *
    2151             :                  * For now, we combine only if all peers in the subgroup have an
    2152             :                  * announcement pending.
    2153             :                  */
    2154           0 :                 all_pending = 1;
    2155             : 
    2156           0 :                 SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
    2157           0 :                         if (cur_paf == paf)
    2158           0 :                                 continue;
    2159             : 
    2160           0 :                         if (cur_paf->t_announce_route)
    2161           0 :                                 continue;
    2162             : 
    2163             :                         all_pending = 0;
    2164             :                         break;
    2165             :                 }
    2166             :         }
    2167             :         /*
    2168             :          * Announce to the peer alone if we were not asked to combine peers,
    2169             :          * or if some peers don't have a route annoucement pending.
    2170             :          */
    2171           0 :         if (!combine || !all_pending) {
    2172           0 :                 update_subgroup_split_peer(paf, NULL);
    2173           0 :                 subgrp = paf->subgroup;
    2174             : 
    2175           0 :                 assert(subgrp && subgrp->update_group);
    2176           0 :                 if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
    2177           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64" %s announcing routes",
    2178             :                                    subgrp->update_group->id, subgrp->id,
    2179             :                                    paf->peer->host);
    2180             : 
    2181           0 :                 subgroup_announce_route(paf->subgroup);
    2182           0 :                 return;
    2183             :         }
    2184             : 
    2185             :         /*
    2186             :          * We will announce routes the entire subgroup.
    2187             :          *
    2188             :          * First stop refresh timers on all the other peers.
    2189             :          */
    2190           0 :         SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
    2191           0 :                 if (cur_paf == paf)
    2192           0 :                         continue;
    2193             : 
    2194           0 :                 bgp_stop_announce_route_timer(cur_paf);
    2195             :         }
    2196             : 
    2197           0 :         if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
    2198           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64" announcing routes to %s, combined into %d peers",
    2199             :                            subgrp->update_group->id, subgrp->id,
    2200             :                            paf->peer->host, subgrp->peer_count);
    2201             : 
    2202           0 :         subgroup_announce_route(subgrp);
    2203             : 
    2204           0 :         SUBGRP_INCR_STAT_BY(subgrp, peer_refreshes_combined,
    2205             :                             subgrp->peer_count - 1);
    2206             : }
    2207             : 
    2208           0 : void subgroup_trigger_write(struct update_subgroup *subgrp)
    2209             : {
    2210           0 :         struct peer_af *paf;
    2211             : 
    2212             :         /*
    2213             :          * For each peer in the subgroup, schedule a job to pull packets from
    2214             :          * the subgroup output queue into their own output queue. This action
    2215             :          * will trigger a write job on the I/O thread.
    2216             :          */
    2217           0 :         SUBGRP_FOREACH_PEER (subgrp, paf)
    2218           0 :                 if (peer_established(paf->peer))
    2219           0 :                         thread_add_timer_msec(
    2220             :                                 bm->master, bgp_generate_updgrp_packets,
    2221             :                                 paf->peer, 0,
    2222             :                                 &paf->peer->t_generate_updgrp_packets);
    2223           0 : }
    2224             : 
    2225           0 : int update_group_clear_update_dbg(struct update_group *updgrp, void *arg)
    2226             : {
    2227           0 :         UPDGRP_PEER_DBG_OFF(updgrp);
    2228           0 :         return UPDWALK_CONTINUE;
    2229             : }
    2230             : 
    2231             : /* Return true if we should addpath encode NLRI to this peer */
    2232           0 : bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi)
    2233             : {
    2234           0 :         return (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV)
    2235           0 :                 && CHECK_FLAG(peer->af_cap[afi][safi],
    2236             :                               PEER_CAP_ADDPATH_AF_RX_RCV));
    2237             : }
    2238             : 
    2239           0 : bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
    2240             :                          afi_t afi, safi_t safi)
    2241             : {
    2242           0 :         return (bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi) ||
    2243           0 :                 (safi == SAFI_LABELED_UNICAST &&
    2244           0 :                  bgp_addpath_tx_path(peer->addpath_type[afi][SAFI_UNICAST],
    2245             :                                      bpi)));
    2246             : }
    2247             : 
    2248           0 : bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
    2249             :                         bool addpath_capable, afi_t afi, safi_t safi)
    2250             : {
    2251           0 :         return (CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) ||
    2252           0 :                 (addpath_capable && bgp_addpath_capable(bpi, peer, afi, safi)));
    2253             : }

Generated by: LCOV version v1.16-topotato