back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_mpath.c (source / functions) Hit Total Coverage
Test: test_bgp_rmap_extcommunity_none.py::TestBGPExtCommunity Lines: 117 374 31.3 %
Date: 2023-02-24 18:37:31 Functions: 13 24 54.2 %

          Line data    Source code
       1             : /*
       2             :  * BGP Multipath
       3             :  * Copyright (C) 2010 Google Inc.
       4             :  *
       5             :  * This file is part of Quagga
       6             :  *
       7             :  * Quagga is free software; you can redistribute it and/or modify it
       8             :  * under the terms of the GNU General Public License as published by the
       9             :  * Free Software Foundation; either version 2, or (at your option) any
      10             :  * later version.
      11             :  *
      12             :  * Quagga is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "command.h"
      25             : #include "prefix.h"
      26             : #include "linklist.h"
      27             : #include "sockunion.h"
      28             : #include "memory.h"
      29             : #include "queue.h"
      30             : #include "filter.h"
      31             : 
      32             : #include "bgpd/bgpd.h"
      33             : #include "bgpd/bgp_table.h"
      34             : #include "bgpd/bgp_route.h"
      35             : #include "bgpd/bgp_attr.h"
      36             : #include "bgpd/bgp_debug.h"
      37             : #include "bgpd/bgp_aspath.h"
      38             : #include "bgpd/bgp_community.h"
      39             : #include "bgpd/bgp_ecommunity.h"
      40             : #include "bgpd/bgp_lcommunity.h"
      41             : #include "bgpd/bgp_mpath.h"
      42             : 
      43             : /*
      44             :  * bgp_maximum_paths_set
      45             :  *
      46             :  * Record maximum-paths configuration for BGP instance
      47             :  */
      48          84 : int bgp_maximum_paths_set(struct bgp *bgp, afi_t afi, safi_t safi, int peertype,
      49             :                           uint16_t maxpaths, bool same_clusterlen)
      50             : {
      51          84 :         if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
      52             :                 return -1;
      53             : 
      54          84 :         switch (peertype) {
      55          42 :         case BGP_PEER_IBGP:
      56          42 :                 bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
      57          42 :                 bgp->maxpaths[afi][safi].same_clusterlen = same_clusterlen;
      58          42 :                 break;
      59          42 :         case BGP_PEER_EBGP:
      60          42 :                 bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
      61          42 :                 break;
      62             :         default:
      63             :                 return -1;
      64             :         }
      65             : 
      66             :         return 0;
      67             : }
      68             : 
      69             : /*
      70             :  * bgp_maximum_paths_unset
      71             :  *
      72             :  * Remove maximum-paths configuration from BGP instance
      73             :  */
      74           0 : int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
      75             :                             int peertype)
      76             : {
      77           0 :         if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
      78             :                 return -1;
      79             : 
      80           0 :         switch (peertype) {
      81           0 :         case BGP_PEER_IBGP:
      82           0 :                 bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
      83           0 :                 bgp->maxpaths[afi][safi].same_clusterlen = false;
      84           0 :                 break;
      85           0 :         case BGP_PEER_EBGP:
      86           0 :                 bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
      87           0 :                 break;
      88             :         default:
      89             :                 return -1;
      90             :         }
      91             : 
      92             :         return 0;
      93             : }
      94             : 
      95             : /*
      96             :  * bgp_interface_same
      97             :  *
      98             :  * Return true if ifindex for ifp1 and ifp2 are the same, else return false.
      99             :  */
     100           0 : static int bgp_interface_same(struct interface *ifp1, struct interface *ifp2)
     101             : {
     102           0 :         if (!ifp1 && !ifp2)
     103             :                 return 1;
     104             : 
     105           0 :         if (!ifp1 && ifp2)
     106             :                 return 0;
     107             : 
     108           0 :         if (ifp1 && !ifp2)
     109             :                 return 0;
     110             : 
     111           0 :         return (ifp1->ifindex == ifp2->ifindex);
     112             : }
     113             : 
     114             : 
     115             : /*
     116             :  * bgp_path_info_nexthop_cmp
     117             :  *
     118             :  * Compare the nexthops of two paths. Return value is less than, equal to,
     119             :  * or greater than zero if bpi1 is respectively less than, equal to,
     120             :  * or greater than bpi2.
     121             :  */
     122           0 : int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
     123             :                               struct bgp_path_info *bpi2)
     124             : {
     125           0 :         int compare;
     126           0 :         struct in6_addr addr1, addr2;
     127             : 
     128           0 :         compare = IPV4_ADDR_CMP(&bpi1->attr->nexthop, &bpi2->attr->nexthop);
     129           0 :         if (!compare) {
     130           0 :                 if (bpi1->attr->mp_nexthop_len == bpi2->attr->mp_nexthop_len) {
     131           0 :                         switch (bpi1->attr->mp_nexthop_len) {
     132           0 :                         case BGP_ATTR_NHLEN_IPV4:
     133             :                         case BGP_ATTR_NHLEN_VPNV4:
     134           0 :                                 compare = IPV4_ADDR_CMP(
     135             :                                         &bpi1->attr->mp_nexthop_global_in,
     136             :                                         &bpi2->attr->mp_nexthop_global_in);
     137           0 :                                 break;
     138           0 :                         case BGP_ATTR_NHLEN_IPV6_GLOBAL:
     139             :                         case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
     140           0 :                                 compare = IPV6_ADDR_CMP(
     141             :                                         &bpi1->attr->mp_nexthop_global,
     142             :                                         &bpi2->attr->mp_nexthop_global);
     143           0 :                                 break;
     144           0 :                         case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
     145           0 :                                 addr1 = (bpi1->attr->mp_nexthop_prefer_global)
     146             :                                                 ? bpi1->attr->mp_nexthop_global
     147           0 :                                                 : bpi1->attr->mp_nexthop_local;
     148           0 :                                 addr2 = (bpi2->attr->mp_nexthop_prefer_global)
     149             :                                                 ? bpi2->attr->mp_nexthop_global
     150           0 :                                                 : bpi2->attr->mp_nexthop_local;
     151             : 
     152           0 :                                 if (!bpi1->attr->mp_nexthop_prefer_global
     153           0 :                                     && !bpi2->attr->mp_nexthop_prefer_global)
     154           0 :                                         compare = !bgp_interface_same(
     155           0 :                                                 bpi1->peer->ifp,
     156           0 :                                                 bpi2->peer->ifp);
     157             : 
     158           0 :                                 if (!compare)
     159           0 :                                         compare = IPV6_ADDR_CMP(&addr1, &addr2);
     160             :                                 break;
     161             :                         }
     162             :                 }
     163             : 
     164             :                 /* This can happen if one IPv6 peer sends you global and
     165             :                  * link-local
     166             :                  * nexthops but another IPv6 peer only sends you global
     167             :                  */
     168           0 :                 else if (bpi1->attr->mp_nexthop_len
     169             :                                  == BGP_ATTR_NHLEN_IPV6_GLOBAL
     170           0 :                          || bpi1->attr->mp_nexthop_len
     171             :                                     == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
     172           0 :                         compare = IPV6_ADDR_CMP(&bpi1->attr->mp_nexthop_global,
     173             :                                                 &bpi2->attr->mp_nexthop_global);
     174           0 :                         if (!compare) {
     175           0 :                                 if (bpi1->attr->mp_nexthop_len
     176             :                                     < bpi2->attr->mp_nexthop_len)
     177             :                                         compare = -1;
     178             :                                 else
     179             :                                         compare = 1;
     180             :                         }
     181             :                 }
     182             :         }
     183             : 
     184             :         /*
     185             :          * If both nexthops are same then check
     186             :          * if they belong to same VRF
     187             :          */
     188           0 :         if (!compare && bpi1->attr->nh_type != NEXTHOP_TYPE_BLACKHOLE) {
     189           0 :                 if (bpi1->extra && bpi1->extra->bgp_orig && bpi2->extra
     190           0 :                     && bpi2->extra->bgp_orig) {
     191           0 :                         if (bpi1->extra->bgp_orig->vrf_id
     192           0 :                             != bpi2->extra->bgp_orig->vrf_id) {
     193           0 :                                 compare = 1;
     194             :                         }
     195             :                 }
     196             :         }
     197             : 
     198           0 :         return compare;
     199             : }
     200             : 
     201             : /*
     202             :  * bgp_path_info_mpath_cmp
     203             :  *
     204             :  * This function determines our multipath list ordering. By ordering
     205             :  * the list we can deterministically select which paths are included
     206             :  * in the multipath set. The ordering also helps in detecting changes
     207             :  * in the multipath selection so we can detect whether to send an
     208             :  * update to zebra.
     209             :  *
     210             :  * The order of paths is determined first by received nexthop, and then
     211             :  * by peer address if the nexthops are the same.
     212             :  */
     213           0 : static int bgp_path_info_mpath_cmp(void *val1, void *val2)
     214             : {
     215           0 :         struct bgp_path_info *bpi1, *bpi2;
     216           0 :         int compare;
     217             : 
     218           0 :         bpi1 = val1;
     219           0 :         bpi2 = val2;
     220             : 
     221           0 :         compare = bgp_path_info_nexthop_cmp(bpi1, bpi2);
     222             : 
     223           0 :         if (!compare) {
     224           0 :                 if (!bpi1->peer->su_remote && !bpi2->peer->su_remote)
     225             :                         compare = 0;
     226           0 :                 else if (!bpi1->peer->su_remote)
     227             :                         compare = 1;
     228           0 :                 else if (!bpi2->peer->su_remote)
     229             :                         compare = -1;
     230             :                 else
     231           0 :                         compare = sockunion_cmp(bpi1->peer->su_remote,
     232             :                                                 bpi2->peer->su_remote);
     233             :         }
     234             : 
     235           0 :         return compare;
     236             : }
     237             : 
     238             : /*
     239             :  * bgp_mp_list_init
     240             :  *
     241             :  * Initialize the mp_list, which holds the list of multipaths
     242             :  * selected by bgp_best_selection
     243             :  */
     244           6 : void bgp_mp_list_init(struct list *mp_list)
     245             : {
     246           6 :         assert(mp_list);
     247           6 :         memset(mp_list, 0, sizeof(struct list));
     248           6 :         mp_list->cmp = bgp_path_info_mpath_cmp;
     249           6 : }
     250             : 
     251             : /*
     252             :  * bgp_mp_list_clear
     253             :  *
     254             :  * Clears all entries out of the mp_list
     255             :  */
     256           6 : void bgp_mp_list_clear(struct list *mp_list)
     257             : {
     258           6 :         assert(mp_list);
     259           6 :         list_delete_all_node(mp_list);
     260           6 : }
     261             : 
     262             : /*
     263             :  * bgp_mp_list_add
     264             :  *
     265             :  * Adds a multipath entry to the mp_list
     266             :  */
     267           6 : void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
     268             : {
     269           6 :         assert(mp_list && mpinfo);
     270           6 :         listnode_add_sort(mp_list, mpinfo);
     271           6 : }
     272             : 
     273             : /*
     274             :  * bgp_path_info_mpath_new
     275             :  *
     276             :  * Allocate and zero memory for a new bgp_path_info_mpath element
     277             :  */
     278           0 : static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
     279             : {
     280           0 :         struct bgp_path_info_mpath *new_mpath;
     281             : 
     282           0 :         new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
     283             :                             sizeof(struct bgp_path_info_mpath));
     284             : 
     285           0 :         return new_mpath;
     286             : }
     287             : 
     288             : /*
     289             :  * bgp_path_info_mpath_free
     290             :  *
     291             :  * Release resources for a bgp_path_info_mpath element and zero out pointer
     292             :  */
     293           4 : void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
     294             : {
     295           4 :         if (mpath && *mpath) {
     296           0 :                 if ((*mpath)->mp_attr)
     297           0 :                         bgp_attr_unintern(&(*mpath)->mp_attr);
     298           0 :                 XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
     299             :         }
     300           4 : }
     301             : 
     302             : /*
     303             :  * bgp_path_info_mpath_get
     304             :  *
     305             :  * Fetch the mpath element for the given bgp_path_info. Used for
     306             :  * doing lazy allocation.
     307             :  */
     308             : static struct bgp_path_info_mpath *
     309           0 : bgp_path_info_mpath_get(struct bgp_path_info *path)
     310             : {
     311           0 :         struct bgp_path_info_mpath *mpath;
     312             : 
     313           0 :         if (!path)
     314             :                 return NULL;
     315             : 
     316           0 :         if (!path->mpath) {
     317           0 :                 mpath = bgp_path_info_mpath_new();
     318           0 :                 path->mpath = mpath;
     319           0 :                 mpath->mp_info = path;
     320             :         }
     321           0 :         return path->mpath;
     322             : }
     323             : 
     324             : /*
     325             :  * bgp_path_info_mpath_enqueue
     326             :  *
     327             :  * Enqueue a path onto the multipath list given the previous multipath
     328             :  * list entry
     329             :  */
     330           0 : static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info,
     331             :                                         struct bgp_path_info *path)
     332             : {
     333           0 :         struct bgp_path_info_mpath *prev, *mpath;
     334             : 
     335           0 :         prev = bgp_path_info_mpath_get(prev_info);
     336           0 :         mpath = bgp_path_info_mpath_get(path);
     337           0 :         if (!prev || !mpath)
     338             :                 return;
     339             : 
     340           0 :         mpath->mp_next = prev->mp_next;
     341           0 :         mpath->mp_prev = prev;
     342           0 :         if (prev->mp_next)
     343           0 :                 prev->mp_next->mp_prev = mpath;
     344           0 :         prev->mp_next = mpath;
     345             : 
     346           0 :         SET_FLAG(path->flags, BGP_PATH_MULTIPATH);
     347             : }
     348             : 
     349             : /*
     350             :  * bgp_path_info_mpath_dequeue
     351             :  *
     352             :  * Remove a path from the multipath list
     353             :  */
     354          10 : void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
     355             : {
     356          10 :         struct bgp_path_info_mpath *mpath = path->mpath;
     357          10 :         if (!mpath)
     358             :                 return;
     359           0 :         if (mpath->mp_prev)
     360           0 :                 mpath->mp_prev->mp_next = mpath->mp_next;
     361           0 :         if (mpath->mp_next)
     362           0 :                 mpath->mp_next->mp_prev = mpath->mp_prev;
     363           0 :         mpath->mp_next = mpath->mp_prev = NULL;
     364           0 :         UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH);
     365             : }
     366             : 
     367             : /*
     368             :  * bgp_path_info_mpath_next
     369             :  *
     370             :  * Given a bgp_path_info, return the next multipath entry
     371             :  */
     372           6 : struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path)
     373             : {
     374           4 :         if (!path->mpath || !path->mpath->mp_next)
     375             :                 return NULL;
     376           0 :         return path->mpath->mp_next->mp_info;
     377             : }
     378             : 
     379             : /*
     380             :  * bgp_path_info_mpath_first
     381             :  *
     382             :  * Given bestpath bgp_path_info, return the first multipath entry.
     383             :  */
     384           2 : struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path)
     385             : {
     386           0 :         return bgp_path_info_mpath_next(path);
     387             : }
     388             : 
     389             : /*
     390             :  * bgp_path_info_mpath_count
     391             :  *
     392             :  * Given the bestpath bgp_path_info, return the number of multipath entries
     393             :  */
     394          32 : uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path)
     395             : {
     396          24 :         if (!path->mpath)
     397             :                 return 0;
     398           0 :         return path->mpath->mp_count;
     399             : }
     400             : 
     401             : /*
     402             :  * bgp_path_info_mpath_count_set
     403             :  *
     404             :  * Sets the count of multipaths into bestpath's mpath element
     405             :  */
     406           8 : static void bgp_path_info_mpath_count_set(struct bgp_path_info *path,
     407             :                                           uint16_t count)
     408             : {
     409           8 :         struct bgp_path_info_mpath *mpath;
     410           8 :         if (!count && !path->mpath)
     411             :                 return;
     412           0 :         mpath = bgp_path_info_mpath_get(path);
     413           0 :         if (!mpath)
     414             :                 return;
     415           0 :         mpath->mp_count = count;
     416             : }
     417             : 
     418             : /*
     419             :  * bgp_path_info_mpath_lb_update
     420             :  *
     421             :  * Update cumulative info related to link-bandwidth
     422             :  */
     423           8 : static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set,
     424             :                                           bool all_paths_lb, uint64_t cum_bw)
     425             : {
     426           8 :         struct bgp_path_info_mpath *mpath;
     427             : 
     428           8 :         mpath = path->mpath;
     429           8 :         if (mpath == NULL) {
     430           8 :                 if (!set || (cum_bw == 0 && !all_paths_lb))
     431             :                         return;
     432             : 
     433           0 :                 mpath = bgp_path_info_mpath_get(path);
     434           0 :                 if (!mpath)
     435             :                         return;
     436             :         }
     437           0 :         if (set) {
     438           0 :                 if (cum_bw)
     439           0 :                         SET_FLAG(mpath->mp_flags, BGP_MP_LB_PRESENT);
     440             :                 else
     441           0 :                         UNSET_FLAG(mpath->mp_flags, BGP_MP_LB_PRESENT);
     442           0 :                 if (all_paths_lb)
     443           0 :                         SET_FLAG(mpath->mp_flags, BGP_MP_LB_ALL);
     444             :                 else
     445           0 :                         UNSET_FLAG(mpath->mp_flags, BGP_MP_LB_ALL);
     446           0 :                 mpath->cum_bw = cum_bw;
     447             :         } else {
     448           0 :                 mpath->mp_flags = 0;
     449           0 :                 mpath->cum_bw = 0;
     450             :         }
     451             : }
     452             : 
     453             : /*
     454             :  * bgp_path_info_mpath_attr
     455             :  *
     456             :  * Given bestpath bgp_path_info, return aggregated attribute set used
     457             :  * for advertising the multipath route
     458             :  */
     459           6 : struct attr *bgp_path_info_mpath_attr(struct bgp_path_info *path)
     460             : {
     461           0 :         if (!path->mpath)
     462             :                 return NULL;
     463           0 :         return path->mpath->mp_attr;
     464             : }
     465             : 
     466             : /*
     467             :  * bgp_path_info_chkwtd
     468             :  *
     469             :  * Return if we should attempt to do weighted ECMP or not
     470             :  * The path passed in is the bestpath.
     471             :  */
     472          16 : bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path)
     473             : {
     474             :         /* Check if told to ignore weights or not multipath */
     475          16 :         if (bgp->lb_handling == BGP_LINK_BW_IGNORE_BW || !path->mpath)
     476             :                 return false;
     477             : 
     478             :         /* All paths in multipath should have associated weight (bandwidth)
     479             :          * unless told explicitly otherwise.
     480             :          */
     481           0 :         if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING &&
     482             :             bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING)
     483           0 :                 return (path->mpath->mp_flags & BGP_MP_LB_ALL);
     484             : 
     485             :         /* At least one path should have bandwidth. */
     486           0 :         return (path->mpath->mp_flags & BGP_MP_LB_PRESENT);
     487             : }
     488             : 
     489             : /*
     490             :  * bgp_path_info_mpath_attr
     491             :  *
     492             :  * Given bestpath bgp_path_info, return cumulative bandwidth
     493             :  * computed for all multipaths with bandwidth info
     494             :  */
     495           2 : uint64_t bgp_path_info_mpath_cumbw(struct bgp_path_info *path)
     496             : {
     497           0 :         if (!path->mpath)
     498             :                 return 0;
     499           0 :         return path->mpath->cum_bw;
     500             : }
     501             : 
     502             : /*
     503             :  * bgp_path_info_mpath_attr_set
     504             :  *
     505             :  * Sets the aggregated attribute into bestpath's mpath element
     506             :  */
     507           0 : static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path,
     508             :                                          struct attr *attr)
     509             : {
     510           0 :         struct bgp_path_info_mpath *mpath;
     511           0 :         if (!attr && !path->mpath)
     512             :                 return;
     513           0 :         mpath = bgp_path_info_mpath_get(path);
     514           0 :         if (!mpath)
     515             :                 return;
     516           0 :         mpath->mp_attr = attr;
     517             : }
     518             : 
     519             : /*
     520             :  * bgp_path_info_mpath_update
     521             :  *
     522             :  * Compare and sync up the multipath list with the mp_list generated by
     523             :  * bgp_best_selection
     524             :  */
     525           6 : void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest,
     526             :                                 struct bgp_path_info *new_best,
     527             :                                 struct bgp_path_info *old_best,
     528             :                                 struct list *mp_list,
     529             :                                 struct bgp_maxpaths_cfg *mpath_cfg)
     530             : {
     531           6 :         uint16_t maxpaths, mpath_count, old_mpath_count;
     532           6 :         uint32_t bwval;
     533           6 :         uint64_t cum_bw, old_cum_bw;
     534           6 :         struct listnode *mp_node, *mp_next_node;
     535           6 :         struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
     536           6 :         int mpath_changed, debug;
     537           6 :         bool all_paths_lb;
     538           6 :         char path_buf[PATH_ADDPATH_STR_BUFFER];
     539             : 
     540           6 :         mpath_changed = 0;
     541           6 :         maxpaths = multipath_num;
     542           6 :         mpath_count = 0;
     543           6 :         cur_mpath = NULL;
     544           6 :         old_mpath_count = 0;
     545           6 :         old_cum_bw = cum_bw = 0;
     546           6 :         prev_mpath = new_best;
     547           6 :         mp_node = listhead(mp_list);
     548           6 :         debug = bgp_debug_bestpath(dest);
     549             : 
     550           6 :         if (new_best) {
     551           6 :                 mpath_count++;
     552           6 :                 if (new_best != old_best)
     553           4 :                         bgp_path_info_mpath_dequeue(new_best);
     554           6 :                 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
     555             :                                    ? mpath_cfg->maxpaths_ibgp
     556             :                                    : mpath_cfg->maxpaths_ebgp;
     557             :         }
     558             : 
     559           6 :         if (old_best) {
     560           2 :                 cur_mpath = bgp_path_info_mpath_first(old_best);
     561           2 :                 old_mpath_count = bgp_path_info_mpath_count(old_best);
     562           2 :                 old_cum_bw = bgp_path_info_mpath_cumbw(old_best);
     563           2 :                 bgp_path_info_mpath_count_set(old_best, 0);
     564           2 :                 bgp_path_info_mpath_lb_update(old_best, false, false, 0);
     565           2 :                 bgp_path_info_mpath_dequeue(old_best);
     566             :         }
     567             : 
     568           6 :         if (debug)
     569           0 :                 zlog_debug(
     570             :                         "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64,
     571             :                         bgp_dest_to_rnode(dest), bgp->name_pretty,
     572             :                         new_best ? new_best->peer->host : "NONE",
     573             :                         mp_list ? listcount(mp_list) : 0, old_mpath_count,
     574             :                         old_cum_bw);
     575             : 
     576             :         /*
     577             :          * We perform an ordered walk through both lists in parallel.
     578             :          * The reason for the ordered walk is that if there are paths
     579             :          * that were previously multipaths and are still multipaths, the walk
     580             :          * should encounter them in both lists at the same time. Otherwise
     581             :          * there will be paths that are in one list or another, and we
     582             :          * will deal with these separately.
     583             :          *
     584             :          * Note that new_best might be somewhere in the mp_list, so we need
     585             :          * to skip over it
     586             :          */
     587             :         all_paths_lb = true; /* We'll reset if any path doesn't have LB. */
     588          12 :         while (mp_node || cur_mpath) {
     589           6 :                 struct bgp_path_info *tmp_info;
     590             : 
     591             :                 /*
     592             :                  * We can bail out of this loop if all existing paths on the
     593             :                  * multipath list have been visited (for cleanup purposes) and
     594             :                  * the maxpath requirement is fulfulled
     595             :                  */
     596           6 :                 if (!cur_mpath && (mpath_count >= maxpaths))
     597             :                         break;
     598             : 
     599           6 :                 mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
     600          12 :                 next_mpath =
     601           6 :                         cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
     602           6 :                 tmp_info = mp_node ? listgetdata(mp_node) : NULL;
     603             : 
     604           6 :                 if (debug)
     605           0 :                         zlog_debug(
     606             :                                 "%pRN(%s): comparing candidate %s with existing mpath %s",
     607             :                                 bgp_dest_to_rnode(dest), bgp->name_pretty,
     608             :                                 tmp_info ? tmp_info->peer->host : "NONE",
     609             :                                 cur_mpath ? cur_mpath->peer->host : "NONE");
     610             : 
     611             :                 /*
     612             :                  * If equal, the path was a multipath and is still a multipath.
     613             :                  * Insert onto new multipath list if maxpaths allows.
     614             :                  */
     615           6 :                 if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
     616           0 :                         list_delete_node(mp_list, mp_node);
     617           0 :                         bgp_path_info_mpath_dequeue(cur_mpath);
     618           0 :                         if ((mpath_count < maxpaths)
     619           0 :                             && prev_mpath
     620           0 :                             && bgp_path_info_nexthop_cmp(prev_mpath,
     621             :                                                          cur_mpath)) {
     622           0 :                                 bgp_path_info_mpath_enqueue(prev_mpath,
     623             :                                                             cur_mpath);
     624           0 :                                 prev_mpath = cur_mpath;
     625           0 :                                 mpath_count++;
     626           0 :                                 if (ecommunity_linkbw_present(
     627             :                                             bgp_attr_get_ecommunity(
     628           0 :                                                     cur_mpath->attr),
     629             :                                             &bwval))
     630           0 :                                         cum_bw += bwval;
     631             :                                 else
     632             :                                         all_paths_lb = false;
     633           0 :                                 if (debug) {
     634           0 :                                         bgp_path_info_path_with_addpath_rx_str(
     635             :                                                 cur_mpath, path_buf,
     636             :                                                 sizeof(path_buf));
     637           0 :                                         zlog_debug(
     638             :                                                 "%pRN: %s is still multipath, cur count %d",
     639             :                                                 bgp_dest_to_rnode(dest),
     640             :                                                 path_buf, mpath_count);
     641             :                                 }
     642             :                         } else {
     643           0 :                                 mpath_changed = 1;
     644           0 :                                 if (debug) {
     645           0 :                                         bgp_path_info_path_with_addpath_rx_str(
     646             :                                                 cur_mpath, path_buf,
     647             :                                                 sizeof(path_buf));
     648           0 :                                         zlog_debug(
     649             :                                                 "%pRN: remove mpath %s nexthop %pI4, cur count %d",
     650             :                                                 bgp_dest_to_rnode(dest),
     651             :                                                 path_buf,
     652             :                                                 &cur_mpath->attr->nexthop,
     653             :                                                 mpath_count);
     654             :                                 }
     655             :                         }
     656           0 :                         mp_node = mp_next_node;
     657           0 :                         cur_mpath = next_mpath;
     658           0 :                         continue;
     659             :                 }
     660             : 
     661           6 :                 if (cur_mpath
     662           0 :                     && (!mp_node
     663           0 :                         || (bgp_path_info_mpath_cmp(cur_mpath,
     664           0 :                                                     listgetdata(mp_node))
     665             :                             < 0))) {
     666             :                         /*
     667             :                          * If here, we have an old multipath and either the
     668             :                          * mp_list
     669             :                          * is finished or the next mp_node points to a later
     670             :                          * multipath, so we need to purge this path from the
     671             :                          * multipath list
     672             :                          */
     673           0 :                         bgp_path_info_mpath_dequeue(cur_mpath);
     674           0 :                         mpath_changed = 1;
     675           0 :                         if (debug) {
     676           0 :                                 bgp_path_info_path_with_addpath_rx_str(
     677             :                                         cur_mpath, path_buf, sizeof(path_buf));
     678           0 :                                 zlog_debug(
     679             :                                         "%pRN: remove mpath %s nexthop %pI4, cur count %d",
     680             :                                         bgp_dest_to_rnode(dest), path_buf,
     681             :                                         &cur_mpath->attr->nexthop, mpath_count);
     682             :                         }
     683             :                         cur_mpath = next_mpath;
     684             :                 } else {
     685             :                         /*
     686             :                          * If here, we have a path on the mp_list that was not
     687             :                          * previously
     688             :                          * a multipath (due to non-equivalance or maxpaths
     689             :                          * exceeded),
     690             :                          * or the matching multipath is sorted later in the
     691             :                          * multipath
     692             :                          * list. Before we enqueue the path on the new multipath
     693             :                          * list,
     694             :                          * make sure its not on the old_best multipath list or
     695             :                          * referenced
     696             :                          * via next_mpath:
     697             :                          * - If next_mpath points to this new path, update
     698             :                          * next_mpath to
     699             :                          *   point to the multipath after this one
     700             :                          * - Dequeue the path from the multipath list just to
     701             :                          * make sure
     702             :                          */
     703           6 :                         new_mpath = listgetdata(mp_node);
     704           6 :                         list_delete_node(mp_list, mp_node);
     705           6 :                         assert(new_mpath);
     706           6 :                         assert(prev_mpath);
     707           6 :                         if ((mpath_count < maxpaths) && (new_mpath != new_best)
     708           0 :                             && bgp_path_info_nexthop_cmp(prev_mpath,
     709             :                                                          new_mpath)) {
     710           0 :                                 bgp_path_info_mpath_dequeue(new_mpath);
     711             : 
     712           0 :                                 bgp_path_info_mpath_enqueue(prev_mpath,
     713             :                                                             new_mpath);
     714           0 :                                 prev_mpath = new_mpath;
     715           0 :                                 mpath_changed = 1;
     716           0 :                                 mpath_count++;
     717           0 :                                 if (ecommunity_linkbw_present(
     718             :                                             bgp_attr_get_ecommunity(
     719           0 :                                                     new_mpath->attr),
     720             :                                             &bwval))
     721           0 :                                         cum_bw += bwval;
     722             :                                 else
     723             :                                         all_paths_lb = false;
     724           0 :                                 if (debug) {
     725           0 :                                         bgp_path_info_path_with_addpath_rx_str(
     726             :                                                 new_mpath, path_buf,
     727             :                                                 sizeof(path_buf));
     728           0 :                                         zlog_debug(
     729             :                                                 "%pRN: add mpath %s nexthop %pI4, cur count %d",
     730             :                                                 bgp_dest_to_rnode(dest),
     731             :                                                 path_buf,
     732             :                                                 &new_mpath->attr->nexthop,
     733             :                                                 mpath_count);
     734             :                                 }
     735             :                         }
     736             :                         mp_node = mp_next_node;
     737             :                 }
     738             :         }
     739             : 
     740           6 :         if (new_best) {
     741           6 :                 bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
     742           6 :                 if (mpath_count <= 1 ||
     743           0 :                     !ecommunity_linkbw_present(
     744           0 :                             bgp_attr_get_ecommunity(new_best->attr), &bwval))
     745             :                         all_paths_lb = false;
     746             :                 else
     747           0 :                         cum_bw += bwval;
     748           6 :                 bgp_path_info_mpath_lb_update(new_best, true,
     749             :                                               all_paths_lb, cum_bw);
     750             : 
     751           6 :                 if (debug)
     752           0 :                         zlog_debug(
     753             :                                 "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64,
     754             :                                 bgp_dest_to_rnode(dest), bgp->name_pretty,
     755             :                                 mpath_count, mpath_changed ? "YES" : "NO",
     756             :                                 all_paths_lb, cum_bw);
     757             : 
     758           6 :                 if (mpath_changed
     759           6 :                     || (bgp_path_info_mpath_count(new_best) != old_mpath_count))
     760           0 :                         SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
     761           6 :                 if ((mpath_count - 1) != old_mpath_count ||
     762             :                     old_cum_bw != cum_bw)
     763           0 :                         SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG);
     764             :         }
     765           6 : }
     766             : 
     767             : /*
     768             :  * bgp_mp_dmed_deselect
     769             :  *
     770             :  * Clean up multipath information for BGP_PATH_DMED_SELECTED path that
     771             :  * is not selected as best path
     772             :  */
     773           0 : void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
     774             : {
     775           0 :         struct bgp_path_info *mpinfo, *mpnext;
     776             : 
     777           0 :         if (!dmed_best)
     778             :                 return;
     779             : 
     780           0 :         for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo;
     781           0 :              mpinfo = mpnext) {
     782           0 :                 mpnext = bgp_path_info_mpath_next(mpinfo);
     783           0 :                 bgp_path_info_mpath_dequeue(mpinfo);
     784             :         }
     785             : 
     786           0 :         bgp_path_info_mpath_count_set(dmed_best, 0);
     787           0 :         UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
     788           0 :         UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG);
     789           0 :         assert(bgp_path_info_mpath_first(dmed_best) == NULL);
     790             : }
     791             : 
     792             : /*
     793             :  * bgp_path_info_mpath_aggregate_update
     794             :  *
     795             :  * Set the multipath aggregate attribute. We need to see if the
     796             :  * aggregate has changed and then set the ATTR_CHANGED flag on the
     797             :  * bestpath info so that a peer update will be generated. The
     798             :  * change is detected by generating the current attribute,
     799             :  * interning it, and then comparing the interned pointer with the
     800             :  * current value. We can skip this generate/compare step if there
     801             :  * is no change in multipath selection and no attribute change in
     802             :  * any multipath.
     803             :  */
     804           6 : void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
     805             :                                           struct bgp_path_info *old_best)
     806             : {
     807           6 :         struct bgp_path_info *mpinfo;
     808           6 :         struct aspath *aspath;
     809           6 :         struct aspath *asmerge;
     810           6 :         struct attr *new_attr, *old_attr;
     811           6 :         uint8_t origin;
     812           6 :         struct community *community, *commerge;
     813           6 :         struct ecommunity *ecomm, *ecommerge;
     814           6 :         struct lcommunity *lcomm, *lcommerge;
     815           6 :         struct attr attr = {0};
     816             : 
     817           6 :         if (old_best && (old_best != new_best)
     818           0 :             && (old_attr = bgp_path_info_mpath_attr(old_best))) {
     819           0 :                 bgp_attr_unintern(&old_attr);
     820           0 :                 bgp_path_info_mpath_attr_set(old_best, NULL);
     821             :         }
     822             : 
     823           6 :         if (!new_best)
     824           6 :                 return;
     825             : 
     826           6 :         if (!bgp_path_info_mpath_count(new_best)) {
     827           6 :                 if ((new_attr = bgp_path_info_mpath_attr(new_best))) {
     828           0 :                         bgp_attr_unintern(&new_attr);
     829           0 :                         bgp_path_info_mpath_attr_set(new_best, NULL);
     830           0 :                         SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
     831             :                 }
     832           6 :                 return;
     833             :         }
     834             : 
     835           0 :         attr = *new_best->attr;
     836             : 
     837           0 :         if (new_best->peer
     838           0 :             && CHECK_FLAG(new_best->peer->bgp->flags,
     839             :                           BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
     840             : 
     841             :                 /* aggregate attribute from multipath constituents */
     842           0 :                 aspath = aspath_dup(attr.aspath);
     843           0 :                 origin = attr.origin;
     844           0 :                 community =
     845           0 :                         bgp_attr_get_community(&attr)
     846           0 :                                 ? community_dup(bgp_attr_get_community(&attr))
     847           0 :                                 : NULL;
     848           0 :                 ecomm = (bgp_attr_get_ecommunity(&attr))
     849           0 :                                 ? ecommunity_dup(bgp_attr_get_ecommunity(&attr))
     850           0 :                                 : NULL;
     851           0 :                 lcomm = (bgp_attr_get_lcommunity(&attr))
     852           0 :                                 ? lcommunity_dup(bgp_attr_get_lcommunity(&attr))
     853           0 :                                 : NULL;
     854             : 
     855           0 :                 for (mpinfo = bgp_path_info_mpath_first(new_best); mpinfo;
     856           0 :                      mpinfo = bgp_path_info_mpath_next(mpinfo)) {
     857           0 :                         asmerge =
     858           0 :                                 aspath_aggregate(aspath, mpinfo->attr->aspath);
     859           0 :                         aspath_free(aspath);
     860           0 :                         aspath = asmerge;
     861             : 
     862           0 :                         if (origin < mpinfo->attr->origin)
     863             :                                 origin = mpinfo->attr->origin;
     864             : 
     865           0 :                         if (bgp_attr_get_community(mpinfo->attr)) {
     866           0 :                                 if (community) {
     867           0 :                                         commerge = community_merge(
     868             :                                                 community,
     869             :                                                 bgp_attr_get_community(
     870           0 :                                                         mpinfo->attr));
     871           0 :                                         community =
     872           0 :                                                 community_uniq_sort(commerge);
     873           0 :                                         community_free(&commerge);
     874             :                                 } else
     875           0 :                                         community = community_dup(
     876             :                                                 bgp_attr_get_community(
     877           0 :                                                         mpinfo->attr));
     878             :                         }
     879             : 
     880           0 :                         if (bgp_attr_get_ecommunity(mpinfo->attr)) {
     881           0 :                                 if (ecomm) {
     882           0 :                                         ecommerge = ecommunity_merge(
     883             :                                                 ecomm, bgp_attr_get_ecommunity(
     884           0 :                                                                mpinfo->attr));
     885           0 :                                         ecomm = ecommunity_uniq_sort(ecommerge);
     886           0 :                                         ecommunity_free(&ecommerge);
     887             :                                 } else
     888           0 :                                         ecomm = ecommunity_dup(
     889             :                                                 bgp_attr_get_ecommunity(
     890           0 :                                                         mpinfo->attr));
     891             :                         }
     892           0 :                         if (bgp_attr_get_lcommunity(mpinfo->attr)) {
     893           0 :                                 if (lcomm) {
     894           0 :                                         lcommerge = lcommunity_merge(
     895             :                                                 lcomm, bgp_attr_get_lcommunity(
     896           0 :                                                                mpinfo->attr));
     897           0 :                                         lcomm = lcommunity_uniq_sort(lcommerge);
     898           0 :                                         lcommunity_free(&lcommerge);
     899             :                                 } else
     900           0 :                                         lcomm = lcommunity_dup(
     901             :                                                 bgp_attr_get_lcommunity(
     902           0 :                                                         mpinfo->attr));
     903             :                         }
     904             :                 }
     905             : 
     906           0 :                 attr.aspath = aspath;
     907           0 :                 attr.origin = origin;
     908           0 :                 if (community)
     909           0 :                         bgp_attr_set_community(&attr, community);
     910           0 :                 if (ecomm)
     911           0 :                         bgp_attr_set_ecommunity(&attr, ecomm);
     912           0 :                 if (lcomm)
     913           0 :                         bgp_attr_set_lcommunity(&attr, lcomm);
     914             : 
     915             :                 /* Zap multipath attr nexthop so we set nexthop to self */
     916           0 :                 attr.nexthop.s_addr = INADDR_ANY;
     917           0 :                 memset(&attr.mp_nexthop_global, 0, sizeof(struct in6_addr));
     918             : 
     919             :                 /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
     920             :         }
     921             : 
     922           0 :         new_attr = bgp_attr_intern(&attr);
     923             : 
     924           0 :         if (new_attr != bgp_path_info_mpath_attr(new_best)) {
     925           0 :                 if ((old_attr = bgp_path_info_mpath_attr(new_best)))
     926           0 :                         bgp_attr_unintern(&old_attr);
     927           0 :                 bgp_path_info_mpath_attr_set(new_best, new_attr);
     928           0 :                 SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
     929             :         } else
     930           0 :                 bgp_attr_unintern(&new_attr);
     931             : }

Generated by: LCOV version v1.16-topotato