On Wed, Nov 25, 2015 at 12:14 PM, Paul Jakma <[email protected]> wrote:
> * bgp_route.c: (bgp_info_cmp) This function is supposed to return a
> preference between the given paths, and does so as binary either or.
> When
> mpath was added, the binary return value was left as is and instead an
> out
> parameter 'paths_eq' was added to indicate the mpath-equality case. It's
> a bit odd, as is the resulting logic in the caller.
>
> Regularise things again by making the function return a strcmp like
> trinary return value of -1,0,1. Get rid of the mpath specific arguments,
> but pass in afi/safi as part of the general context - that plus the
> (struct bgp *) is enough to access configuration.
>
> Update the return values.
>
> The mpath check was testing the IGP metric for equality, even though
> previous to the mpath changes (and consistent with the behaviour of all
> the other tests bar the end), equality results in continuing through to
> the next comparison. Just go back to the previous way - each test finds a
> preference to return, or continues on to let further tests have a go.
>
> (bgp_best_selection) Get rid of the (struct bgp_maxpaths_cfg *) arg, we
> can't add state for every optional feature to the argument list - they
> have to look it up as needed. Do pass through the very general afi/safi
> context though (saves several lookups through the route_node).
>
> Adjust for the new trinary bgp_info_cmp return value and updated args.
> Do the mpath clearing/accumulation in one place, in each loop.
>
> Call to bgp_info_mpath_update similarly gets updated, as there's no cfg
> to
> pass.
>
> (bgp_process_{rsclient,main}) match bgp_best_selection changes.
> * bgp_mpath.c: (bgp_mpath_is_configured_sort) Helper for whether mpath is
> enabled by peer sort.
> (bgp_mpath_is_configured) ditto, generally.
> (bgp_info_mpath_update) caller no longer has the cfg to pass in, look it
> up.
> * bgp_mpath.h: Export the above and Match .c changes.
> ---
> bgpd/bgp_mpath.c | 34 ++++++++++-
> bgpd/bgp_mpath.h | 4 +-
> bgpd/bgp_route.c | 173
> ++++++++++++++++++++++++++-----------------------------
> 3 files changed, 118 insertions(+), 93 deletions(-)
>
> diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
> index 7999d16..db5996e 100644
> --- a/bgpd/bgp_mpath.c
> +++ b/bgpd/bgp_mpath.c
> @@ -39,6 +39,33 @@
> #include "bgpd/bgp_ecommunity.h"
> #include "bgpd/bgp_mpath.h"
>
> +bool
> +bgp_mpath_is_configured_sort (struct bgp *bgp, bgp_peer_sort_t sort,
> + afi_t afi, safi_t safi)
> +{
> + struct bgp_maxpaths_cfg *cfg = &bgp->maxpaths[afi][safi];
> +
> + /* XXX: BGP_DEFAULT_MAXPATHS is 1, and this test only seems to make
> sense
> + * if if it stays 1, so not sure the DEFAULT define is that useful.
> + */
> + switch (sort)
> + {
> + case BGP_PEER_IBGP:
> + return cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS;
>
It would be worth future proofing this (we have a patch to increase
BGP_DEFAULT_MAXPATHS) and return true if cfg->maxpaths_ibgp > 1
> + case BGP_PEER_EBGP:
> + return cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS;
> + default:
> + return false;
> + }
> +}
> +
> +bool
> +bgp_mpath_is_configured (struct bgp *bgp, afi_t afi, safi_t safi)
> +{
> + return bgp_mpath_is_configured_sort (bgp, BGP_PEER_IBGP, afi, safi)
> + || bgp_mpath_is_configured_sort (bgp, BGP_PEER_EBGP, afi, safi);
> +}
> +
> /*
> * bgp_maximum_paths_set
> *
> @@ -395,7 +422,7 @@ bgp_info_mpath_attr_set (struct bgp_info *binfo,
> struct attr *attr)
> void
> bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
> struct bgp_info *old_best, struct list *mp_list,
> - struct bgp_maxpaths_cfg *mpath_cfg)
> + afi_t afi, safi_t safi)
> {
> u_int16_t maxpaths, mpath_count, old_mpath_count;
> struct listnode *mp_node, *mp_next_node;
> @@ -410,8 +437,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct
> bgp_info *new_best,
> old_mpath_count = 0;
> prev_mpath = new_best;
> mp_node = listhead (mp_list);
> + struct bgp_maxpaths_cfg *mpath_cfg;
> debug = BGP_DEBUG (events, EVENTS);
> -
> +
> + mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi];
> +
> if (debug)
> prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
>
> diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h
> index 37b9ac8..2a84d5e 100644
> --- a/bgpd/bgp_mpath.h
> +++ b/bgpd/bgp_mpath.h
> @@ -51,6 +51,8 @@ struct bgp_info_mpath
> /* Functions to support maximum-paths configuration */
> extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int,
> u_int16_t);
> extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int);
> +bool bgp_mpath_is_configured_sort (struct bgp *, bgp_peer_sort_t, afi_t,
> safi_t);
> +bool bgp_mpath_is_configured (struct bgp *, afi_t, safi_t);
>
> /* Functions used by bgp_best_selection to record current
> * multipath selections
> @@ -61,7 +63,7 @@ extern void bgp_mp_list_add (struct list *, struct
> bgp_info *);
> extern void bgp_mp_dmed_deselect (struct bgp_info *);
> extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *,
> struct bgp_info *, struct list *,
> - struct bgp_maxpaths_cfg *);
> + afi_t, safi_t);
> extern void bgp_info_mpath_aggregate_update (struct bgp_info *,
> struct bgp_info *);
>
> diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
> index 316fa5a..1a49cb3 100644
> --- a/bgpd/bgp_route.c
> +++ b/bgpd/bgp_route.c
> @@ -321,10 +321,12 @@ bgp_med_value (struct attr *attr, struct bgp *bgp)
> }
> }
>
> -/* Compare two bgp route entity. br is preferable then return 1. */
> +/* Compare two bgp route entity. Return -1 if new is preferred, 1 if
> exist
> + * is preferred, or 0 if they are the same (usually will only occur if
> + * multipath is enabled */
> static int
> bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info
> *exist,
> - int *paths_eq)
> + afi_t afi, safi_t safi)
> {
> struct attr *newattr, *existattr;
> struct attr_extra *newattre, *existattre;
> @@ -345,13 +347,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> int confed_as_route;
> int ret;
>
> - *paths_eq = 0;
> -
> /* 0. Null check. */
> if (new == NULL)
> - return 0;
> - if (exist == NULL)
> return 1;
> + if (exist == NULL)
> + return -1;
>
> newattr = new->attr;
> existattr = exist->attr;
> @@ -367,9 +367,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> exist_weight = existattre->weight;
>
> if (new_weight > exist_weight)
> - return 1;
> + return -1;
> if (new_weight < exist_weight)
> - return 0;
> + return 1;
>
> /* 2. Local preference check. */
> new_pref = exist_pref = bgp->default_local_pref;
> @@ -380,9 +380,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> exist_pref = existattr->local_pref;
>
> if (new_pref > exist_pref)
> - return 1;
> + return -1;
> if (new_pref < exist_pref)
> - return 0;
> + return 1;
>
> /* 3. Local route check. We prefer:
> * - BGP_ROUTE_STATIC
> @@ -390,9 +390,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> * - BGP_ROUTE_REDISTRIBUTE
> */
> if (! (new->sub_type == BGP_ROUTE_NORMAL))
> - return 1;
> + return -1;
> if (! (exist->sub_type == BGP_ROUTE_NORMAL))
> - return 0;
> + return 1;
>
> /* 4. AS path length check. */
> if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
> @@ -408,26 +408,26 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> aspath_hops += aspath_count_confeds (newattr->aspath);
>
> if ( aspath_hops < (exist_hops + exist_confeds))
> - return 1;
> + return -1;
> if ( aspath_hops > (exist_hops + exist_confeds))
> - return 0;
> + return 1;
> }
> else
> {
> int newhops = aspath_count_hops (newattr->aspath);
>
> if (newhops < exist_hops)
> - return 1;
> + return -1;
> if (newhops > exist_hops)
> - return 0;
> + return 1;
> }
> }
>
> /* 5. Origin check. */
> if (newattr->origin < existattr->origin)
> - return 1;
> + return -1;
> if (newattr->origin > existattr->origin)
> - return 0;
> + return 1;
>
> /* 6. MED check. */
> internal_as_route = (aspath_count_hops (newattr->aspath) == 0
> @@ -448,9 +448,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> exist_med = bgp_med_value (exist->attr, bgp);
>
> if (new_med < exist_med)
> - return 1;
> + return -1;
> if (new_med > exist_med)
> - return 0;
> + return 1;
> }
>
> /* 7. Peer type check. */
> @@ -459,10 +459,10 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
>
> if (new_sort == BGP_PEER_EBGP
> && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED))
> - return 1;
> + return -1;
> if (exist_sort == BGP_PEER_EBGP
> && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED))
> - return 0;
> + return 1;
>
> /* 8. IGP metric check. */
> newm = existm = 0;
> @@ -473,41 +473,32 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> existm = exist->extra->igpmetric;
>
> if (newm < existm)
> - ret = 1;
> + return -1;
> if (newm > existm)
> - ret = 0;
> + return 1;
>
> /* 9. Maximum path check. */
> - if (newm == existm)
> + if (bgp_mpath_is_configured (bgp, afi, safi))
> {
> if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX))
> {
> -
> - /*
> - * For the two paths, all comparison steps till IGP metric
> - * have succeeded - including AS_PATH hop count. Since 'bgp
> - * bestpath as-path multipath-relax' knob is on, we don't need
> - * an exact match of AS_PATH. Thus, mark the paths are equal.
> - * That will trigger both these paths to get into the multipath
> - * array.
> - */
> - *paths_eq = 1;
> + /*
> + * For the two paths, all comparison steps till IGP metric
> + * have succeeded - including AS_PATH hop count. Since 'bgp
> + * bestpath as-path multipath-relax' knob is on, we don't need
> + * an exact match of AS_PATH. Thus, mark the paths are equal.
> + * That will trigger both these paths to get into the multipath
> + * array.
> + */
> + return 0;
>
I don't follow how bestpath selection is working when max-paths is
enabled. Say we have two paths who only differ by router-id...we still
need to get to step #11 to determine which is the winner.
Daniel
> }
> else if (new->peer->sort == BGP_PEER_IBGP)
> - {
> - if (aspath_cmp (new->attr->aspath, exist->attr->aspath))
> - *paths_eq = 1;
> - }
> + {
> + if (aspath_cmp (new->attr->aspath, exist->attr->aspath))
> + return 0;
> + }
> else if (new->peer->as == exist->peer->as)
> - *paths_eq = 1;
> - }
> - else
> - {
> - /*
> - * TODO: If unequal cost ibgp multipath is enabled we can
> - * mark the paths as equal here instead of returning
> - */
> - return ret;
> + return 0;
> }
>
> /* 10. If both paths are external, prefer the path that was received
> @@ -519,9 +510,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> && exist_sort == BGP_PEER_EBGP)
> {
> if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED))
> - return 1;
> + return -1;
> if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED))
> - return 0;
> + return 1;
> }
>
> /* 11. Router-ID comparision. */
> @@ -539,9 +530,9 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> exist_id.s_addr = exist->peer->remote_id.s_addr;
>
> if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr))
> - return 1;
> + return -1;
> if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr))
> - return 0;
> + return 1;
>
> /* 12. Cluster length comparision. */
> new_cluster = exist_cluster = 0;
> @@ -552,32 +543,32 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new,
> struct bgp_info *exist,
> exist_cluster = existattre->cluster->length;
>
> if (new_cluster < exist_cluster)
> - return 1;
> + return -1;
> if (new_cluster > exist_cluster)
> - return 0;
> + return 1;
>
> /* 13. Neighbor address comparision. */
> /* Do this only if neither path is "stale" as stale paths do not have
> * valid peer information (as the connection may or may not be up).
> */
> if (CHECK_FLAG (exist->flags, BGP_INFO_STALE))
> - return 1;
> + return -1;
> if (CHECK_FLAG (new->flags, BGP_INFO_STALE))
> - return 0;
> + return 1;
> /* locally configured routes to advertise do not have su_remote */
> if (new->peer->su_remote == NULL)
> - return 0;
> - if (exist->peer->su_remote == NULL)
> return 1;
> + if (exist->peer->su_remote == NULL)
> + return -1;
>
> ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote);
> -
> +
> if (ret == 1)
> - return 0;
> - if (ret == -1)
> return 1;
> + if (ret == -1)
> + return -1;
>
> - return 1;
> + return -1;
> }
>
> static enum filter_type
> @@ -1325,8 +1316,8 @@ struct bgp_info_pair
>
> static void
> bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
> - struct bgp_maxpaths_cfg *mpath_cfg,
> - struct bgp_info_pair *result)
> + struct bgp_info_pair *result,
> + afi_t afi, safi_t safi)
> {
> struct bgp_info *new_select;
> struct bgp_info *old_select;
> @@ -1334,12 +1325,11 @@ bgp_best_selection (struct bgp *bgp, struct
> bgp_node *rn,
> struct bgp_info *ri1;
> struct bgp_info *ri2;
> struct bgp_info *nextri = NULL;
> - int paths_eq, do_mpath;
> + int cmpret, do_mpath;
> struct list mp_list;
> -
> +
> bgp_mp_list_init (&mp_list);
> - do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS ||
> - mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS);
> + do_mpath = bgp_mpath_is_configured (bgp, afi, safi);
>
> /* bgp deterministic-med */
> new_select = NULL;
> @@ -1377,19 +1367,21 @@ bgp_best_selection (struct bgp *bgp, struct
> bgp_node *rn,
> {
> if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
> old_select = ri2;
> - if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq))
> + if ((cmpret = bgp_info_cmp (bgp, ri2, new_select, afi,
> safi))
> + == -1)
> {
> bgp_info_unset_flag (rn, new_select,
> BGP_INFO_DMED_SELECTED);
> new_select = ri2;
> - if (do_mpath && !paths_eq)
> - {
> - bgp_mp_list_clear (&mp_list);
> - bgp_mp_list_add (&mp_list, ri2);
> - }
> }
>
> - if (do_mpath && paths_eq)
> - bgp_mp_list_add (&mp_list, ri2);
> + if (do_mpath)
> + {
> + if (cmpret != 0)
> + bgp_mp_list_clear (&mp_list);
> +
> + if (cmpret == 0 || cmpret == -1)
> + bgp_mp_list_add (&mp_list, ri);
> + }
>
> bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
> }
> @@ -1397,7 +1389,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node
> *rn,
> bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
> bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
>
> - bgp_info_mpath_update (rn, new_select, old_select, &mp_list,
> mpath_cfg);
> + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi,
> safi);
> bgp_mp_list_clear (&mp_list);
> }
>
> @@ -1436,29 +1428,30 @@ bgp_best_selection (struct bgp *bgp, struct
> bgp_node *rn,
> bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
> bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED);
>
> - if (bgp_info_cmp (bgp, ri, new_select, &paths_eq))
> + if ((cmpret = bgp_info_cmp (bgp, ri, new_select, afi, safi)) == -1)
> {
> if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
> bgp_mp_dmed_deselect (new_select);
>
> new_select = ri;
> -
> - if (do_mpath && !paths_eq)
> - {
> - bgp_mp_list_clear (&mp_list);
> - bgp_mp_list_add (&mp_list, ri);
> - }
> }
> - else if (do_mpath && bgp_flag_check (bgp,
> BGP_FLAG_DETERMINISTIC_MED))
> + else if (cmpret == 1 && do_mpath
> + && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
> bgp_mp_dmed_deselect (ri);
>
> - if (do_mpath && paths_eq)
> - bgp_mp_list_add (&mp_list, ri);
> + if (do_mpath)
> + {
> + if (cmpret != 0)
> + bgp_mp_list_clear (&mp_list);
> +
> + if (cmpret == 0 || cmpret == -1)
> + bgp_mp_list_add (&mp_list, ri);
> + }
> }
>
>
> if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
> - bgp_info_mpath_update (rn, new_select, old_select, &mp_list,
> mpath_cfg);
> + bgp_info_mpath_update (rn, new_select, old_select, &mp_list, afi,
> safi);
>
> bgp_info_mpath_aggregate_update (new_select, old_select);
> bgp_mp_list_clear (&mp_list);
> @@ -1542,7 +1535,7 @@ bgp_process_rsclient (struct work_queue *wq, void
> *data)
> struct peer *rsclient = bgp_node_table (rn)->owner;
>
> /* Best path selection. */
> - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new);
> + bgp_best_selection (bgp, rn, &old_and_new, afi, safi);
> new_select = old_and_new.new;
> old_select = old_and_new.old;
>
> @@ -1605,7 +1598,7 @@ bgp_process_main (struct work_queue *wq, void *data)
> struct peer *peer;
>
> /* Best path selection. */
> - bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new);
> + bgp_best_selection (bgp, rn, &old_and_new, afi, safi);
> old_select = old_and_new.old;
> new_select = old_and_new.new;
>
> --
> 2.5.0
>
>
> _______________________________________________
> Quagga-dev mailing list
> [email protected]
> https://lists.quagga.net/mailman/listinfo/quagga-dev
>
_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev