summaryrefslogtreecommitdiff
path: root/bgpd/bgp_mpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_mpath.c')
-rw-r--r--bgpd/bgp_mpath.c1082
1 files changed, 534 insertions, 548 deletions
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index a95c4a008e..3d03d8364a 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -46,27 +46,25 @@
*
* Record maximum-paths configuration for BGP instance
*/
-int
-bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
- int peertype, u_int16_t maxpaths, u_int16_t options)
+int bgp_maximum_paths_set(struct bgp *bgp, afi_t afi, safi_t safi, int peertype,
+ u_int16_t maxpaths, u_int16_t options)
{
- if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
- return -1;
-
- switch (peertype)
- {
- case BGP_PEER_IBGP:
- bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
- bgp->maxpaths[afi][safi].ibgp_flags |= options;
- break;
- case BGP_PEER_EBGP:
- bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
- break;
- default:
- return -1;
- }
-
- return 0;
+ if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
+ return -1;
+
+ switch (peertype) {
+ case BGP_PEER_IBGP:
+ bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
+ bgp->maxpaths[afi][safi].ibgp_flags |= options;
+ break;
+ case BGP_PEER_EBGP:
+ bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
}
/*
@@ -74,27 +72,25 @@ bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
*
* Remove maximum-paths configuration from BGP instance
*/
-int
-bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
- int peertype)
+int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ int peertype)
{
- if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
- return -1;
-
- switch (peertype)
- {
- case BGP_PEER_IBGP:
- bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
- bgp->maxpaths[afi][safi].ibgp_flags = 0;
- break;
- case BGP_PEER_EBGP:
- bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
- break;
- default:
- return -1;
- }
-
- return 0;
+ if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
+ return -1;
+
+ switch (peertype) {
+ case BGP_PEER_IBGP:
+ bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
+ bgp->maxpaths[afi][safi].ibgp_flags = 0;
+ break;
+ case BGP_PEER_EBGP:
+ bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
}
/*
@@ -104,61 +100,61 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
* or greater than zero if bi1 is respectively less than, equal to,
* or greater than bi2.
*/
-int
-bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
+int bgp_info_nexthop_cmp(struct bgp_info *bi1, struct bgp_info *bi2)
{
- struct attr_extra *ae1, *ae2;
- int compare;
-
- ae1 = bi1->attr->extra;
- ae2 = bi2->attr->extra;
-
- compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
- if (!compare && ae1 && ae2)
- {
- if (ae1->mp_nexthop_len == ae2->mp_nexthop_len)
- {
- switch (ae1->mp_nexthop_len)
- {
- case BGP_ATTR_NHLEN_IPV4:
- case BGP_ATTR_NHLEN_VPNV4:
- compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
- &ae2->mp_nexthop_global_in);
- break;
- case BGP_ATTR_NHLEN_IPV6_GLOBAL:
- case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
- &ae2->mp_nexthop_global);
- break;
- case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
- &ae2->mp_nexthop_global);
- if (!compare)
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
- &ae2->mp_nexthop_local);
- break;
- }
- }
-
- /* This can happen if one IPv6 peer sends you global and link-local
- * nexthops but another IPv6 peer only sends you global
- */
- else if (ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
- ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- {
- compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
- &ae2->mp_nexthop_global);
- if (!compare)
- {
- if (ae1->mp_nexthop_len < ae2->mp_nexthop_len)
- compare = -1;
- else
- compare = 1;
- }
- }
- }
-
- return compare;
+ struct attr_extra *ae1, *ae2;
+ int compare;
+
+ ae1 = bi1->attr->extra;
+ ae2 = bi2->attr->extra;
+
+ compare = IPV4_ADDR_CMP(&bi1->attr->nexthop, &bi2->attr->nexthop);
+ if (!compare && ae1 && ae2) {
+ if (ae1->mp_nexthop_len == ae2->mp_nexthop_len) {
+ switch (ae1->mp_nexthop_len) {
+ case BGP_ATTR_NHLEN_IPV4:
+ case BGP_ATTR_NHLEN_VPNV4:
+ compare = IPV4_ADDR_CMP(
+ &ae1->mp_nexthop_global_in,
+ &ae2->mp_nexthop_global_in);
+ break;
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL:
+ case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
+ compare =
+ IPV6_ADDR_CMP(&ae1->mp_nexthop_global,
+ &ae2->mp_nexthop_global);
+ break;
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
+ compare =
+ IPV6_ADDR_CMP(&ae1->mp_nexthop_global,
+ &ae2->mp_nexthop_global);
+ if (!compare)
+ compare = IPV6_ADDR_CMP(
+ &ae1->mp_nexthop_local,
+ &ae2->mp_nexthop_local);
+ break;
+ }
+ }
+
+ /* This can happen if one IPv6 peer sends you global and
+ * link-local
+ * nexthops but another IPv6 peer only sends you global
+ */
+ else if (ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
+ || ae1->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ compare = IPV6_ADDR_CMP(&ae1->mp_nexthop_global,
+ &ae2->mp_nexthop_global);
+ if (!compare) {
+ if (ae1->mp_nexthop_len < ae2->mp_nexthop_len)
+ compare = -1;
+ else
+ compare = 1;
+ }
+ }
+ }
+
+ return compare;
}
/*
@@ -173,30 +169,29 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
* The order of paths is determined first by received nexthop, and then
* by peer address if the nexthops are the same.
*/
-static int
-bgp_info_mpath_cmp (void *val1, void *val2)
+static int bgp_info_mpath_cmp(void *val1, void *val2)
{
- struct bgp_info *bi1, *bi2;
- int compare;
-
- bi1 = val1;
- bi2 = val2;
-
- compare = bgp_info_nexthop_cmp (bi1, bi2);
-
- if (!compare)
- {
- if (!bi1->peer->su_remote && !bi2->peer->su_remote)
- compare = 0;
- else if (!bi1->peer->su_remote)
- compare = 1;
- else if (!bi2->peer->su_remote)
- compare = -1;
- else
- compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote);
- }
-
- return compare;
+ struct bgp_info *bi1, *bi2;
+ int compare;
+
+ bi1 = val1;
+ bi2 = val2;
+
+ compare = bgp_info_nexthop_cmp(bi1, bi2);
+
+ if (!compare) {
+ if (!bi1->peer->su_remote && !bi2->peer->su_remote)
+ compare = 0;
+ else if (!bi1->peer->su_remote)
+ compare = 1;
+ else if (!bi2->peer->su_remote)
+ compare = -1;
+ else
+ compare = sockunion_cmp(bi1->peer->su_remote,
+ bi2->peer->su_remote);
+ }
+
+ return compare;
}
/*
@@ -205,12 +200,11 @@ bgp_info_mpath_cmp (void *val1, void *val2)
* Initialize the mp_list, which holds the list of multipaths
* selected by bgp_best_selection
*/
-void
-bgp_mp_list_init (struct list *mp_list)
+void bgp_mp_list_init(struct list *mp_list)
{
- assert (mp_list);
- memset (mp_list, 0, sizeof (struct list));
- mp_list->cmp = bgp_info_mpath_cmp;
+ assert(mp_list);
+ memset(mp_list, 0, sizeof(struct list));
+ mp_list->cmp = bgp_info_mpath_cmp;
}
/*
@@ -218,11 +212,10 @@ bgp_mp_list_init (struct list *mp_list)
*
* Clears all entries out of the mp_list
*/
-void
-bgp_mp_list_clear (struct list *mp_list)
+void bgp_mp_list_clear(struct list *mp_list)
{
- assert (mp_list);
- list_delete_all_node (mp_list);
+ assert(mp_list);
+ list_delete_all_node(mp_list);
}
/*
@@ -230,11 +223,10 @@ bgp_mp_list_clear (struct list *mp_list)
*
* Adds a multipath entry to the mp_list
*/
-void
-bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo)
+void bgp_mp_list_add(struct list *mp_list, struct bgp_info *mpinfo)
{
- assert (mp_list && mpinfo);
- listnode_add_sort (mp_list, mpinfo);
+ assert(mp_list && mpinfo);
+ listnode_add_sort(mp_list, mpinfo);
}
/*
@@ -242,12 +234,12 @@ bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo)
*
* Allocate and zero memory for a new bgp_info_mpath element
*/
-static struct bgp_info_mpath *
-bgp_info_mpath_new (void)
+static struct bgp_info_mpath *bgp_info_mpath_new(void)
{
- struct bgp_info_mpath *new_mpath;
- new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath));
- return new_mpath;
+ struct bgp_info_mpath *new_mpath;
+ new_mpath =
+ XCALLOC(MTYPE_BGP_MPATH_INFO, sizeof(struct bgp_info_mpath));
+ return new_mpath;
}
/*
@@ -255,16 +247,14 @@ bgp_info_mpath_new (void)
*
* Release resources for a bgp_info_mpath element and zero out pointer
*/
-void
-bgp_info_mpath_free (struct bgp_info_mpath **mpath)
+void bgp_info_mpath_free(struct bgp_info_mpath **mpath)
{
- if (mpath && *mpath)
- {
- if ((*mpath)->mp_attr)
- bgp_attr_unintern (&(*mpath)->mp_attr);
- XFREE (MTYPE_BGP_MPATH_INFO, *mpath);
- *mpath = NULL;
- }
+ if (mpath && *mpath) {
+ if ((*mpath)->mp_attr)
+ bgp_attr_unintern(&(*mpath)->mp_attr);
+ XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
+ *mpath = NULL;
+ }
}
/*
@@ -273,19 +263,17 @@ bgp_info_mpath_free (struct bgp_info_mpath **mpath)
* Fetch the mpath element for the given bgp_info. Used for
* doing lazy allocation.
*/
-static struct bgp_info_mpath *
-bgp_info_mpath_get (struct bgp_info *binfo)
+static struct bgp_info_mpath *bgp_info_mpath_get(struct bgp_info *binfo)
{
- struct bgp_info_mpath *mpath;
- if (!binfo->mpath)
- {
- mpath = bgp_info_mpath_new();
- if (!mpath)
- return NULL;
- binfo->mpath = mpath;
- mpath->mp_info = binfo;
- }
- return binfo->mpath;
+ struct bgp_info_mpath *mpath;
+ if (!binfo->mpath) {
+ mpath = bgp_info_mpath_new();
+ if (!mpath)
+ return NULL;
+ binfo->mpath = mpath;
+ mpath->mp_info = binfo;
+ }
+ return binfo->mpath;
}
/*
@@ -294,23 +282,23 @@ bgp_info_mpath_get (struct bgp_info *binfo)
* Enqueue a path onto the multipath list given the previous multipath
* list entry
*/
-static void
-bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo)
+static void bgp_info_mpath_enqueue(struct bgp_info *prev_info,
+ struct bgp_info *binfo)
{
- struct bgp_info_mpath *prev, *mpath;
+ struct bgp_info_mpath *prev, *mpath;
- prev = bgp_info_mpath_get (prev_info);
- mpath = bgp_info_mpath_get (binfo);
- if (!prev || !mpath)
- return;
+ prev = bgp_info_mpath_get(prev_info);
+ mpath = bgp_info_mpath_get(binfo);
+ if (!prev || !mpath)
+ return;
- mpath->mp_next = prev->mp_next;
- mpath->mp_prev = prev;
- if (prev->mp_next)
- prev->mp_next->mp_prev = mpath;
- prev->mp_next = mpath;
+ mpath->mp_next = prev->mp_next;
+ mpath->mp_prev = prev;
+ if (prev->mp_next)
+ prev->mp_next->mp_prev = mpath;
+ prev->mp_next = mpath;
- SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
+ SET_FLAG(binfo->flags, BGP_INFO_MULTIPATH);
}
/*
@@ -318,18 +306,17 @@ bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo)
*
* Remove a path from the multipath list
*/
-void
-bgp_info_mpath_dequeue (struct bgp_info *binfo)
+void bgp_info_mpath_dequeue(struct bgp_info *binfo)
{
- struct bgp_info_mpath *mpath = binfo->mpath;
- if (!mpath)
- return;
- if (mpath->mp_prev)
- mpath->mp_prev->mp_next = mpath->mp_next;
- if (mpath->mp_next)
- mpath->mp_next->mp_prev = mpath->mp_prev;
- mpath->mp_next = mpath->mp_prev = NULL;
- UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
+ struct bgp_info_mpath *mpath = binfo->mpath;
+ if (!mpath)
+ return;
+ if (mpath->mp_prev)
+ mpath->mp_prev->mp_next = mpath->mp_next;
+ if (mpath->mp_next)
+ mpath->mp_next->mp_prev = mpath->mp_prev;
+ mpath->mp_next = mpath->mp_prev = NULL;
+ UNSET_FLAG(binfo->flags, BGP_INFO_MULTIPATH);
}
/*
@@ -337,12 +324,11 @@ bgp_info_mpath_dequeue (struct bgp_info *binfo)
*
* Given a bgp_info, return the next multipath entry
*/
-struct bgp_info *
-bgp_info_mpath_next (struct bgp_info *binfo)
+struct bgp_info *bgp_info_mpath_next(struct bgp_info *binfo)
{
- if (!binfo->mpath || !binfo->mpath->mp_next)
- return NULL;
- return binfo->mpath->mp_next->mp_info;
+ if (!binfo->mpath || !binfo->mpath->mp_next)
+ return NULL;
+ return binfo->mpath->mp_next->mp_info;
}
/*
@@ -350,10 +336,9 @@ bgp_info_mpath_next (struct bgp_info *binfo)
*
* Given bestpath bgp_info, return the first multipath entry.
*/
-struct bgp_info *
-bgp_info_mpath_first (struct bgp_info *binfo)
+struct bgp_info *bgp_info_mpath_first(struct bgp_info *binfo)
{
- return bgp_info_mpath_next (binfo);
+ return bgp_info_mpath_next(binfo);
}
/*
@@ -361,12 +346,11 @@ bgp_info_mpath_first (struct bgp_info *binfo)
*
* Given the bestpath bgp_info, return the number of multipath entries
*/
-u_int32_t
-bgp_info_mpath_count (struct bgp_info *binfo)
+u_int32_t bgp_info_mpath_count(struct bgp_info *binfo)
{
- if (!binfo->mpath)
- return 0;
- return binfo->mpath->mp_count;
+ if (!binfo->mpath)
+ return 0;
+ return binfo->mpath->mp_count;
}
/*
@@ -374,16 +358,15 @@ bgp_info_mpath_count (struct bgp_info *binfo)
*
* Sets the count of multipaths into bestpath's mpath element
*/
-static void
-bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count)
+static void bgp_info_mpath_count_set(struct bgp_info *binfo, u_int32_t count)
{
- struct bgp_info_mpath *mpath;
- if (!count && !binfo->mpath)
- return;
- mpath = bgp_info_mpath_get (binfo);
- if (!mpath)
- return;
- mpath->mp_count = count;
+ struct bgp_info_mpath *mpath;
+ if (!count && !binfo->mpath)
+ return;
+ mpath = bgp_info_mpath_get(binfo);
+ if (!mpath)
+ return;
+ mpath->mp_count = count;
}
/*
@@ -392,12 +375,11 @@ bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count)
* Given bestpath bgp_info, return aggregated attribute set used
* for advertising the multipath route
*/
-struct attr *
-bgp_info_mpath_attr (struct bgp_info *binfo)
+struct attr *bgp_info_mpath_attr(struct bgp_info *binfo)
{
- if (!binfo->mpath)
- return NULL;
- return binfo->mpath->mp_attr;
+ if (!binfo->mpath)
+ return NULL;
+ return binfo->mpath->mp_attr;
}
/*
@@ -405,16 +387,15 @@ bgp_info_mpath_attr (struct bgp_info *binfo)
*
* Sets the aggregated attribute into bestpath's mpath element
*/
-static void
-bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr)
+static void bgp_info_mpath_attr_set(struct bgp_info *binfo, struct attr *attr)
{
- struct bgp_info_mpath *mpath;
- if (!attr && !binfo->mpath)
- return;
- mpath = bgp_info_mpath_get (binfo);
- if (!mpath)
- return;
- mpath->mp_attr = attr;
+ struct bgp_info_mpath *mpath;
+ if (!attr && !binfo->mpath)
+ return;
+ mpath = bgp_info_mpath_get(binfo);
+ if (!mpath)
+ return;
+ mpath->mp_attr = attr;
}
/*
@@ -423,196 +404,210 @@ bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr)
* Compare and sync up the multipath list with the mp_list generated by
* bgp_best_selection
*/
-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)
+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)
{
- u_int16_t maxpaths, mpath_count, old_mpath_count;
- struct listnode *mp_node, *mp_next_node;
- struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
- int mpath_changed, debug;
- char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN];
- char path_buf[PATH_ADDPATH_STR_BUFFER];
-
- mpath_changed = 0;
- maxpaths = multipath_num;
- mpath_count = 0;
- cur_mpath = NULL;
- old_mpath_count = 0;
- prev_mpath = new_best;
- mp_node = listhead (mp_list);
- debug = bgp_debug_bestpath(&rn->p);
-
- if (debug)
- prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
-
- if (new_best)
- {
- mpath_count++;
- if (new_best != old_best)
- bgp_info_mpath_dequeue (new_best);
- maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
- mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp;
- }
-
- if (old_best)
- {
- cur_mpath = bgp_info_mpath_first (old_best);
- old_mpath_count = bgp_info_mpath_count (old_best);
- bgp_info_mpath_count_set (old_best, 0);
- bgp_info_mpath_dequeue (old_best);
- }
-
- if (debug)
- zlog_debug("%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
- pfx_buf, new_best ? new_best->peer->host : "NONE",
- listcount (mp_list), old_mpath_count);
-
- /*
- * We perform an ordered walk through both lists in parallel.
- * The reason for the ordered walk is that if there are paths
- * that were previously multipaths and are still multipaths, the walk
- * should encounter them in both lists at the same time. Otherwise
- * there will be paths that are in one list or another, and we
- * will deal with these separately.
- *
- * Note that new_best might be somewhere in the mp_list, so we need
- * to skip over it
- */
- while (mp_node || cur_mpath)
- {
- struct bgp_info *tmp_info;
-
- /*
- * We can bail out of this loop if all existing paths on the
- * multipath list have been visited (for cleanup purposes) and
- * the maxpath requirement is fulfulled
- */
- if (!cur_mpath && (mpath_count >= maxpaths))
- break;
-
- mp_next_node = mp_node ? listnextnode (mp_node) : NULL;
- next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL;
- tmp_info = mp_node ? listgetdata (mp_node) : NULL;
-
- if (debug)
- zlog_debug("%s: comparing candidate %s with existing mpath %s",
- pfx_buf, tmp_info ? tmp_info->peer->host : "NONE",
- cur_mpath ? cur_mpath->peer->host : "NONE");
-
- /*
- * If equal, the path was a multipath and is still a multipath.
- * Insert onto new multipath list if maxpaths allows.
- */
- if (mp_node && (listgetdata (mp_node) == cur_mpath))
- {
- list_delete_node (mp_list, mp_node);
- bgp_info_mpath_dequeue (cur_mpath);
- if ((mpath_count < maxpaths) &&
- bgp_info_nexthop_cmp (prev_mpath, cur_mpath))
- {
- bgp_info_mpath_enqueue (prev_mpath, cur_mpath);
- prev_mpath = cur_mpath;
- mpath_count++;
- if (debug)
- {
- bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
- zlog_debug("%s: %s is still multipath, cur count %d",
- pfx_buf, path_buf, mpath_count);
- }
- }
- else
- {
- mpath_changed = 1;
- if (debug)
- {
- bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
- zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
- inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
- nh_buf[0], sizeof (nh_buf[0])),
- mpath_count);
- }
- }
- mp_node = mp_next_node;
- cur_mpath = next_mpath;
- continue;
- }
-
- if (cur_mpath && (!mp_node ||
- (bgp_info_mpath_cmp (cur_mpath,
- listgetdata (mp_node)) < 0)))
- {
- /*
- * If here, we have an old multipath and either the mp_list
- * is finished or the next mp_node points to a later
- * multipath, so we need to purge this path from the
- * multipath list
- */
- bgp_info_mpath_dequeue (cur_mpath);
- mpath_changed = 1;
- if (debug)
- {
- bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
- zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
- inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
- nh_buf[0], sizeof (nh_buf[0])),
- mpath_count);
- }
- cur_mpath = next_mpath;
- }
- else
- {
- /*
- * If here, we have a path on the mp_list that was not previously
- * a multipath (due to non-equivalance or maxpaths exceeded),
- * or the matching multipath is sorted later in the multipath
- * list. Before we enqueue the path on the new multipath list,
- * make sure its not on the old_best multipath list or referenced
- * via next_mpath:
- * - If next_mpath points to this new path, update next_mpath to
- * point to the multipath after this one
- * - Dequeue the path from the multipath list just to make sure
- */
- new_mpath = listgetdata (mp_node);
- list_delete_node (mp_list, mp_node);
- if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
- bgp_info_nexthop_cmp (prev_mpath, new_mpath))
- {
- if (new_mpath == next_mpath)
- bgp_info_mpath_next (new_mpath);
- bgp_info_mpath_dequeue (new_mpath);
-
- bgp_info_mpath_enqueue (prev_mpath, new_mpath);
- prev_mpath = new_mpath;
- mpath_changed = 1;
- mpath_count++;
- if (debug)
- {
- bgp_info_path_with_addpath_rx_str(new_mpath, path_buf);
- zlog_debug ("%s: add mpath %s nexthop %s, cur count %d",
- pfx_buf, path_buf,
- inet_ntop (AF_INET, &new_mpath->attr->nexthop,
- nh_buf[0], sizeof (nh_buf[0])),
- mpath_count);
- }
- }
- mp_node = mp_next_node;
- }
- }
-
- if (new_best)
- {
- if (debug)
- zlog_debug("%s: New mpath count (incl newbest) %d mpath-change %s",
- pfx_buf, mpath_count, mpath_changed ? "YES" : "NO");
-
- bgp_info_mpath_count_set (new_best, mpath_count-1);
- if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count))
- SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG);
- }
+ u_int16_t maxpaths, mpath_count, old_mpath_count;
+ struct listnode *mp_node, *mp_next_node;
+ struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
+ int mpath_changed, debug;
+ char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN];
+ char path_buf[PATH_ADDPATH_STR_BUFFER];
+
+ mpath_changed = 0;
+ maxpaths = multipath_num;
+ mpath_count = 0;
+ cur_mpath = NULL;
+ old_mpath_count = 0;
+ prev_mpath = new_best;
+ mp_node = listhead(mp_list);
+ debug = bgp_debug_bestpath(&rn->p);
+
+ if (debug)
+ prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
+
+ if (new_best) {
+ mpath_count++;
+ if (new_best != old_best)
+ bgp_info_mpath_dequeue(new_best);
+ maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
+ ? mpath_cfg->maxpaths_ibgp
+ : mpath_cfg->maxpaths_ebgp;
+ }
+
+ if (old_best) {
+ cur_mpath = bgp_info_mpath_first(old_best);
+ old_mpath_count = bgp_info_mpath_count(old_best);
+ bgp_info_mpath_count_set(old_best, 0);
+ bgp_info_mpath_dequeue(old_best);
+ }
+
+ if (debug)
+ zlog_debug(
+ "%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
+ pfx_buf, new_best ? new_best->peer->host : "NONE",
+ listcount(mp_list), old_mpath_count);
+
+ /*
+ * We perform an ordered walk through both lists in parallel.
+ * The reason for the ordered walk is that if there are paths
+ * that were previously multipaths and are still multipaths, the walk
+ * should encounter them in both lists at the same time. Otherwise
+ * there will be paths that are in one list or another, and we
+ * will deal with these separately.
+ *
+ * Note that new_best might be somewhere in the mp_list, so we need
+ * to skip over it
+ */
+ while (mp_node || cur_mpath) {
+ struct bgp_info *tmp_info;
+
+ /*
+ * We can bail out of this loop if all existing paths on the
+ * multipath list have been visited (for cleanup purposes) and
+ * the maxpath requirement is fulfulled
+ */
+ if (!cur_mpath && (mpath_count >= maxpaths))
+ break;
+
+ mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
+ next_mpath = cur_mpath ? bgp_info_mpath_next(cur_mpath) : NULL;
+ tmp_info = mp_node ? listgetdata(mp_node) : NULL;
+
+ if (debug)
+ zlog_debug(
+ "%s: comparing candidate %s with existing mpath %s",
+ pfx_buf,
+ tmp_info ? tmp_info->peer->host : "NONE",
+ cur_mpath ? cur_mpath->peer->host : "NONE");
+
+ /*
+ * If equal, the path was a multipath and is still a multipath.
+ * Insert onto new multipath list if maxpaths allows.
+ */
+ if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
+ list_delete_node(mp_list, mp_node);
+ bgp_info_mpath_dequeue(cur_mpath);
+ if ((mpath_count < maxpaths)
+ && bgp_info_nexthop_cmp(prev_mpath, cur_mpath)) {
+ bgp_info_mpath_enqueue(prev_mpath, cur_mpath);
+ prev_mpath = cur_mpath;
+ mpath_count++;
+ if (debug) {
+ bgp_info_path_with_addpath_rx_str(
+ cur_mpath, path_buf);
+ zlog_debug(
+ "%s: %s is still multipath, cur count %d",
+ pfx_buf, path_buf, mpath_count);
+ }
+ } else {
+ mpath_changed = 1;
+ if (debug) {
+ bgp_info_path_with_addpath_rx_str(
+ cur_mpath, path_buf);
+ zlog_debug(
+ "%s: remove mpath %s nexthop %s, cur count %d",
+ pfx_buf, path_buf,
+ inet_ntop(AF_INET,
+ &cur_mpath->attr
+ ->nexthop,
+ nh_buf[0],
+ sizeof(nh_buf[0])),
+ mpath_count);
+ }
+ }
+ mp_node = mp_next_node;
+ cur_mpath = next_mpath;
+ continue;
+ }
+
+ if (cur_mpath
+ && (!mp_node
+ || (bgp_info_mpath_cmp(cur_mpath, listgetdata(mp_node))
+ < 0))) {
+ /*
+ * If here, we have an old multipath and either the
+ * mp_list
+ * is finished or the next mp_node points to a later
+ * multipath, so we need to purge this path from the
+ * multipath list
+ */
+ bgp_info_mpath_dequeue(cur_mpath);
+ mpath_changed = 1;
+ if (debug) {
+ bgp_info_path_with_addpath_rx_str(cur_mpath,
+ path_buf);
+ zlog_debug(
+ "%s: remove mpath %s nexthop %s, cur count %d",
+ pfx_buf, path_buf,
+ inet_ntop(AF_INET,
+ &cur_mpath->attr->nexthop,
+ nh_buf[0], sizeof(nh_buf[0])),
+ mpath_count);
+ }
+ cur_mpath = next_mpath;
+ } else {
+ /*
+ * If here, we have a path on the mp_list that was not
+ * previously
+ * a multipath (due to non-equivalance or maxpaths
+ * exceeded),
+ * or the matching multipath is sorted later in the
+ * multipath
+ * list. Before we enqueue the path on the new multipath
+ * list,
+ * make sure its not on the old_best multipath list or
+ * referenced
+ * via next_mpath:
+ * - If next_mpath points to this new path, update
+ * next_mpath to
+ * point to the multipath after this one
+ * - Dequeue the path from the multipath list just to
+ * make sure
+ */
+ new_mpath = listgetdata(mp_node);
+ list_delete_node(mp_list, mp_node);
+ if ((mpath_count < maxpaths) && (new_mpath != new_best)
+ && bgp_info_nexthop_cmp(prev_mpath, new_mpath)) {
+ if (new_mpath == next_mpath)
+ bgp_info_mpath_next(new_mpath);
+ bgp_info_mpath_dequeue(new_mpath);
+
+ bgp_info_mpath_enqueue(prev_mpath, new_mpath);
+ prev_mpath = new_mpath;
+ mpath_changed = 1;
+ mpath_count++;
+ if (debug) {
+ bgp_info_path_with_addpath_rx_str(
+ new_mpath, path_buf);
+ zlog_debug(
+ "%s: add mpath %s nexthop %s, cur count %d",
+ pfx_buf, path_buf,
+ inet_ntop(AF_INET,
+ &new_mpath->attr
+ ->nexthop,
+ nh_buf[0],
+ sizeof(nh_buf[0])),
+ mpath_count);
+ }
+ }
+ mp_node = mp_next_node;
+ }
+ }
+
+ if (new_best) {
+ if (debug)
+ zlog_debug(
+ "%s: New mpath count (incl newbest) %d mpath-change %s",
+ pfx_buf, mpath_count,
+ mpath_changed ? "YES" : "NO");
+
+ bgp_info_mpath_count_set(new_best, mpath_count - 1);
+ if (mpath_changed
+ || (bgp_info_mpath_count(new_best) != old_mpath_count))
+ SET_FLAG(new_best->flags, BGP_INFO_MULTIPATH_CHG);
+ }
}
/*
@@ -621,23 +616,22 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
* Clean up multipath information for BGP_INFO_DMED_SELECTED path that
* is not selected as best path
*/
-void
-bgp_mp_dmed_deselect (struct bgp_info *dmed_best)
+void bgp_mp_dmed_deselect(struct bgp_info *dmed_best)
{
- struct bgp_info *mpinfo, *mpnext;
+ struct bgp_info *mpinfo, *mpnext;
- if (!dmed_best)
- return;
+ if (!dmed_best)
+ return;
- for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext)
- {
- mpnext = bgp_info_mpath_next (mpinfo);
- bgp_info_mpath_dequeue (mpinfo);
- }
+ for (mpinfo = bgp_info_mpath_first(dmed_best); mpinfo;
+ mpinfo = mpnext) {
+ mpnext = bgp_info_mpath_next(mpinfo);
+ bgp_info_mpath_dequeue(mpinfo);
+ }
- bgp_info_mpath_count_set (dmed_best, 0);
- UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG);
- assert (bgp_info_mpath_first (dmed_best) == 0);
+ bgp_info_mpath_count_set(dmed_best, 0);
+ UNSET_FLAG(dmed_best->flags, BGP_INFO_MULTIPATH_CHG);
+ assert(bgp_info_mpath_first(dmed_best) == 0);
}
/*
@@ -652,135 +646,127 @@ bgp_mp_dmed_deselect (struct bgp_info *dmed_best)
* is no change in multipath selection and no attribute change in
* any multipath.
*/
-void
-bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
- struct bgp_info *old_best)
+void bgp_info_mpath_aggregate_update(struct bgp_info *new_best,
+ struct bgp_info *old_best)
{
- struct bgp_info *mpinfo;
- struct aspath *aspath;
- struct aspath *asmerge;
- struct attr *new_attr, *old_attr;
- u_char origin;
- struct community *community, *commerge;
- struct ecommunity *ecomm, *ecommerge;
- struct lcommunity *lcomm, *lcommerge;
- struct attr_extra *ae;
- struct attr attr = { 0 };
-
- if (old_best && (old_best != new_best) &&
- (old_attr = bgp_info_mpath_attr (old_best)))
- {
- bgp_attr_unintern (&old_attr);
- bgp_info_mpath_attr_set (old_best, NULL);
- }
-
- if (!new_best)
- return;
-
- if (!bgp_info_mpath_count (new_best))
- {
- if ((new_attr = bgp_info_mpath_attr (new_best)))
- {
- bgp_attr_unintern (&new_attr);
- bgp_info_mpath_attr_set (new_best, NULL);
- SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
- }
- return;
- }
-
- bgp_attr_dup (&attr, new_best->attr);
-
- if (new_best->peer &&
- bgp_flag_check (new_best->peer->bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET))
- {
-
- /* aggregate attribute from multipath constituents */
- aspath = aspath_dup (attr.aspath);
- origin = attr.origin;
- community = attr.community ? community_dup (attr.community) : NULL;
- ae = attr.extra;
- ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
- lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
-
- for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
- mpinfo = bgp_info_mpath_next (mpinfo))
- {
- asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath);
- aspath_free (aspath);
- aspath = asmerge;
-
- if (origin < mpinfo->attr->origin)
- origin = mpinfo->attr->origin;
-
- if (mpinfo->attr->community)
- {
- if (community)
- {
- commerge = community_merge (community, mpinfo->attr->community);
- community = community_uniq_sort (commerge);
- community_free (commerge);
- }
- else
- community = community_dup (mpinfo->attr->community);
- }
-
- ae = mpinfo->attr->extra;
- if (ae && ae->ecommunity)
- {
- if (ecomm)
- {
- ecommerge = ecommunity_merge (ecomm, ae->ecommunity);
- ecomm = ecommunity_uniq_sort (ecommerge);
- ecommunity_free (&ecommerge);
- }
- else
- ecomm = ecommunity_dup (ae->ecommunity);
- }
- if (ae && ae->lcommunity)
- {
- if (lcomm)
- {
- lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
- lcomm = lcommunity_uniq_sort (lcommerge);
- lcommunity_free (&lcommerge);
- }
- else
- lcomm = lcommunity_dup (ae->lcommunity);
- }
- }
-
- attr.aspath = aspath;
- attr.origin = origin;
- if (community)
- {
- attr.community = community;
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
- }
- if (ecomm)
- {
- ae = bgp_attr_extra_get (&attr);
- ae->ecommunity = ecomm;
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
- }
-
- /* Zap multipath attr nexthop so we set nexthop to self */
- attr.nexthop.s_addr = 0;
- if (attr.extra)
- memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
-
- /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
- }
-
- new_attr = bgp_attr_intern (&attr);
- bgp_attr_extra_free (&attr);
-
- if (new_attr != bgp_info_mpath_attr (new_best))
- {
- if ((old_attr = bgp_info_mpath_attr (new_best)))
- bgp_attr_unintern (&old_attr);
- bgp_info_mpath_attr_set (new_best, new_attr);
- SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
- }
- else
- bgp_attr_unintern (&new_attr);
+ struct bgp_info *mpinfo;
+ struct aspath *aspath;
+ struct aspath *asmerge;
+ struct attr *new_attr, *old_attr;
+ u_char origin;
+ struct community *community, *commerge;
+ struct ecommunity *ecomm, *ecommerge;
+ struct lcommunity *lcomm, *lcommerge;
+ struct attr_extra *ae;
+ struct attr attr = {0};
+
+ if (old_best && (old_best != new_best)
+ && (old_attr = bgp_info_mpath_attr(old_best))) {
+ bgp_attr_unintern(&old_attr);
+ bgp_info_mpath_attr_set(old_best, NULL);
+ }
+
+ if (!new_best)
+ return;
+
+ if (!bgp_info_mpath_count(new_best)) {
+ if ((new_attr = bgp_info_mpath_attr(new_best))) {
+ bgp_attr_unintern(&new_attr);
+ bgp_info_mpath_attr_set(new_best, NULL);
+ SET_FLAG(new_best->flags, BGP_INFO_ATTR_CHANGED);
+ }
+ return;
+ }
+
+ bgp_attr_dup(&attr, new_best->attr);
+
+ if (new_best->peer && bgp_flag_check(new_best->peer->bgp,
+ BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
+
+ /* aggregate attribute from multipath constituents */
+ aspath = aspath_dup(attr.aspath);
+ origin = attr.origin;
+ community =
+ attr.community ? community_dup(attr.community) : NULL;
+ ae = attr.extra;
+ ecomm = (ae && ae->ecommunity) ? ecommunity_dup(ae->ecommunity)
+ : NULL;
+ lcomm = (ae && ae->lcommunity) ? lcommunity_dup(ae->lcommunity)
+ : NULL;
+
+ for (mpinfo = bgp_info_mpath_first(new_best); mpinfo;
+ mpinfo = bgp_info_mpath_next(mpinfo)) {
+ asmerge =
+ aspath_aggregate(aspath, mpinfo->attr->aspath);
+ aspath_free(aspath);
+ aspath = asmerge;
+
+ if (origin < mpinfo->attr->origin)
+ origin = mpinfo->attr->origin;
+
+ if (mpinfo->attr->community) {
+ if (community) {
+ commerge = community_merge(
+ community,
+ mpinfo->attr->community);
+ community =
+ community_uniq_sort(commerge);
+ community_free(commerge);
+ } else
+ community = community_dup(
+ mpinfo->attr->community);
+ }
+
+ ae = mpinfo->attr->extra;
+ if (ae && ae->ecommunity) {
+ if (ecomm) {
+ ecommerge = ecommunity_merge(
+ ecomm, ae->ecommunity);
+ ecomm = ecommunity_uniq_sort(ecommerge);
+ ecommunity_free(&ecommerge);
+ } else
+ ecomm = ecommunity_dup(ae->ecommunity);
+ }
+ if (ae && ae->lcommunity) {
+ if (lcomm) {
+ lcommerge = lcommunity_merge(
+ lcomm, ae->lcommunity);
+ lcomm = lcommunity_uniq_sort(lcommerge);
+ lcommunity_free(&lcommerge);
+ } else
+ lcomm = lcommunity_dup(ae->lcommunity);
+ }
+ }
+
+ attr.aspath = aspath;
+ attr.origin = origin;
+ if (community) {
+ attr.community = community;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
+ }
+ if (ecomm) {
+ ae = bgp_attr_extra_get(&attr);
+ ae->ecommunity = ecomm;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
+ }
+
+ /* Zap multipath attr nexthop so we set nexthop to self */
+ attr.nexthop.s_addr = 0;
+ if (attr.extra)
+ memset(&attr.extra->mp_nexthop_global, 0,
+ sizeof(struct in6_addr));
+
+ /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
+ }
+
+ new_attr = bgp_attr_intern(&attr);
+ bgp_attr_extra_free(&attr);
+
+ if (new_attr != bgp_info_mpath_attr(new_best)) {
+ if ((old_attr = bgp_info_mpath_attr(new_best)))
+ bgp_attr_unintern(&old_attr);
+ bgp_info_mpath_attr_set(new_best, new_attr);
+ SET_FLAG(new_best->flags, BGP_INFO_ATTR_CHANGED);
+ } else
+ bgp_attr_unintern(&new_attr);
}