]> git.puffer.fish Git - matthieu/frr.git/commitdiff
Add 'debug bgp bestpath'
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:04:02 +0000 (18:04 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:04:02 +0000 (18:04 -0700)
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_mpath.c
bgpd/bgp_route.c

index b1fc7726f1e765497844db1a55d78de0ac32660d..f86c3f7b27e4eb931e57e50fcf7d1eee1839f5d0 100644 (file)
@@ -46,6 +46,7 @@ unsigned long conf_bgp_debug_packet;
 unsigned long conf_bgp_debug_filter;
 unsigned long conf_bgp_debug_keepalive;
 unsigned long conf_bgp_debug_update;
+unsigned long conf_bgp_debug_bestpath;
 unsigned long conf_bgp_debug_zebra;
 unsigned long conf_bgp_debug_nht;
 unsigned long conf_bgp_debug_update_groups;
@@ -57,6 +58,7 @@ unsigned long term_bgp_debug_packet;
 unsigned long term_bgp_debug_filter;
 unsigned long term_bgp_debug_keepalive;
 unsigned long term_bgp_debug_update;
+unsigned long term_bgp_debug_bestpath;
 unsigned long term_bgp_debug_zebra;
 unsigned long term_bgp_debug_nht;
 unsigned long term_bgp_debug_update_groups;
@@ -66,6 +68,7 @@ struct list *bgp_debug_keepalive_peers = NULL;
 struct list *bgp_debug_update_out_peers = NULL;
 struct list *bgp_debug_update_in_peers = NULL;
 struct list *bgp_debug_update_prefixes = NULL;
+struct list *bgp_debug_bestpath_prefixes = NULL;
 struct list *bgp_debug_zebra_prefixes = NULL;
 
 /* messages for BGP-4 status */
@@ -814,6 +817,126 @@ DEFUN (no_debug_bgp_keepalive_peer,
   return CMD_SUCCESS;
 }
 
+/* debug bgp bestpath */
+DEFUN (debug_bgp_bestpath_prefix,
+       debug_bgp_bestpath_prefix_cmd,
+       "debug bgp bestpath (A.B.C.D/M|X:X::X:X/M)",
+       DEBUG_STR
+       BGP_STR
+       "BGP bestpath\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "IPv6 prefix <network>/<length>\n")
+
+{
+  struct prefix *argv_p;
+  int ret;
+
+  argv_p = prefix_new();
+  ret = str2prefix (argv[0], argv_p);
+  if (!ret)
+    {
+      prefix_free(argv_p);
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+
+  if (!bgp_debug_bestpath_prefixes)
+    bgp_debug_bestpath_prefixes = list_new ();
+
+  if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, argv_p))
+    {
+      vty_out (vty, "BGP bestptah debugging is already enabled for %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, argv_p);
+
+  if (vty->node == CONFIG_NODE)
+    {
+      DEBUG_ON (bestpath, BESTPATH);
+    }
+  else
+    {
+      TERM_DEBUG_ON (bestpath, BESTPATH);
+      vty_out (vty, "BGP bestpath debugging is on for %s%s", argv[0], VTY_NEWLINE);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_bestpath_prefix,
+       no_debug_bgp_bestpath_prefix_cmd,
+       "no debug bgp bestpath (A.B.C.D/M|X:X::X:X/M)",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP bestpath\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "IPv6 prefix <network>/<length>\n")
+
+{
+  struct prefix *argv_p;
+  int found_prefix = 0;
+  int ret;
+
+  argv_p = prefix_new();
+  ret = str2prefix (argv[0], argv_p);
+  if (!ret)
+    {
+      prefix_free(argv_p);
+      vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (bgp_debug_bestpath_prefixes && !list_isempty(bgp_debug_bestpath_prefixes))
+    {
+      found_prefix = bgp_debug_list_remove_entry(bgp_debug_bestpath_prefixes, NULL, argv_p);
+
+      if (list_isempty(bgp_debug_bestpath_prefixes))
+        {
+          if (vty->node == CONFIG_NODE)
+            {
+              DEBUG_OFF (bestpath, BESTPATH);
+            }
+          else
+            {
+              TERM_DEBUG_OFF (bestpath, BESTPATH);
+              vty_out (vty, "BGP bestpath debugging (per prefix) is off%s", VTY_NEWLINE);
+            }
+        }
+    }
+
+  if (found_prefix)
+    vty_out (vty, "BGP bestpath debugging is off for %s%s", argv[0], VTY_NEWLINE);
+  else
+    vty_out (vty, "BGP bestpath debugging was not enabled for %s%s", argv[0], VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_bgp_bestpath,
+       no_debug_bgp_bestpath_cmd,
+       "no debug bgp bestpath",
+       NO_STR
+       DEBUG_STR
+       BGP_STR
+       "BGP bestpath\n")
+{
+  bgp_debug_list_free(bgp_debug_bestpath_prefixes);
+
+  if (vty->node == CONFIG_NODE)
+    DEBUG_OFF (bestpath, BESTPATH);
+  else
+    {
+      TERM_DEBUG_OFF (bestpath, BESTPATH);
+      vty_out (vty, "BGP bestpath debugging is off%s", VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+
+
 /* debug bgp updates */
 DEFUN (debug_bgp_update,
        debug_bgp_update_cmd,
@@ -1376,6 +1499,7 @@ DEFUN (no_debug_bgp,
   bgp_debug_list_free(bgp_debug_update_in_peers);
   bgp_debug_list_free(bgp_debug_update_out_peers);
   bgp_debug_list_free(bgp_debug_update_prefixes);
+  bgp_debug_list_free(bgp_debug_bestpath_prefixes);
   bgp_debug_list_free(bgp_debug_zebra_prefixes);
 
   bgp_debug_clear_updgrp_update_dbg(vty->index);
@@ -1384,6 +1508,7 @@ DEFUN (no_debug_bgp,
   TERM_DEBUG_OFF (update, UPDATE_IN);
   TERM_DEBUG_OFF (update, UPDATE_OUT);
   TERM_DEBUG_OFF (update, UPDATE_PREFIX);
+  TERM_DEBUG_OFF (bestpath, BESTPATH);
   TERM_DEBUG_OFF (as4, AS4);
   TERM_DEBUG_OFF (as4, AS4_SEGMENT);
   TERM_DEBUG_OFF (neighbor_events, NEIGHBOR_EVENTS);
@@ -1431,6 +1556,10 @@ DEFUN (show_debugging_bgp,
     bgp_debug_list_print (vty, "  BGP updates debugging is on (outbound)",
                           bgp_debug_update_out_peers);
 
+  if (BGP_DEBUG (bestpath, BESTPATH))
+    bgp_debug_list_print (vty, "  BGP bestpath debugging is on for",
+                          bgp_debug_bestpath_prefixes);
+
   if (BGP_DEBUG (zebra, ZEBRA))
     bgp_debug_list_print (vty, "  BGP zebra debugging is on",
                           bgp_debug_zebra_prefixes);
@@ -1481,6 +1610,12 @@ bgp_config_write_debug (struct vty *vty)
       write++;
     }
 
+  if (CONF_BGP_DEBUG (bestpath, BESTPATH))
+    {
+      vty_out (vty, "debug bgp bestpath%s", VTY_NEWLINE);
+      write++;
+    }
+
   if (CONF_BGP_DEBUG (neighbor_events, NEIGHBOR_EVENTS))
     {
       vty_out (vty, "debug bgp neighbor-events%s", VTY_NEWLINE);
@@ -1541,6 +1676,8 @@ bgp_debug_init (void)
   install_element (CONFIG_NODE, &debug_bgp_zebra_cmd);
   install_element (ENABLE_NODE, &debug_bgp_update_groups_cmd);
   install_element (CONFIG_NODE, &debug_bgp_update_groups_cmd);
+  install_element (ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd);
+  install_element (CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd);
 
   /* deb bgp updates [in|out] A.B.C.D */
   install_element (ENABLE_NODE, &debug_bgp_update_direct_peer_cmd);
@@ -1590,6 +1727,10 @@ bgp_debug_init (void)
   install_element (ENABLE_NODE, &no_debug_bgp_update_groups_cmd);
   install_element (CONFIG_NODE, &no_debug_bgp_update_groups_cmd);
   install_element (ENABLE_NODE, &no_debug_bgp_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_bestpath_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_bestpath_cmd);
+  install_element (ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
+  install_element (CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
 }
 
 /* Return true if this prefix is on the per_prefix_list of prefixes to debug
@@ -1710,6 +1851,20 @@ bgp_debug_update (struct peer *peer, struct prefix *p,
   return 0;
 }
 
+int
+bgp_debug_bestpath (struct prefix *p)
+{
+  if (BGP_DEBUG (bestpath, BESTPATH))
+    {
+      if (bgp_debug_per_prefix (p, term_bgp_debug_bestpath,
+                                BGP_DEBUG_BESTPATH,
+                                bgp_debug_bestpath_prefixes))
+        return 1;
+    }
+
+  return 0;
+}
+
 int
 bgp_debug_zebra (struct prefix *p)
 {
index a80d00440e95df6864b43b7837b110700c896e27..54c0ac685aaf3603601c70f8753fab3cd68f5b89 100644 (file)
@@ -64,6 +64,7 @@ extern unsigned long conf_bgp_debug_neighbor_events;
 extern unsigned long conf_bgp_debug_packet;
 extern unsigned long conf_bgp_debug_keepalive;
 extern unsigned long conf_bgp_debug_update;
+extern unsigned long conf_bgp_debug_bestpath;
 extern unsigned long conf_bgp_debug_zebra;
 extern unsigned long conf_bgp_debug_nht;
 extern unsigned long conf_bgp_debug_update_groups;
@@ -73,6 +74,7 @@ extern unsigned long term_bgp_debug_neighbor_events;
 extern unsigned long term_bgp_debug_packet;
 extern unsigned long term_bgp_debug_keepalive;
 extern unsigned long term_bgp_debug_update;
+extern unsigned long term_bgp_debug_bestpath;
 extern unsigned long term_bgp_debug_zebra;
 extern unsigned long term_bgp_debug_nht;
 extern unsigned long term_bgp_debug_update_groups;
@@ -82,6 +84,7 @@ extern struct list *bgp_debug_keepalive_peers;
 extern struct list *bgp_debug_update_in_peers;
 extern struct list *bgp_debug_update_out_peers;
 extern struct list *bgp_debug_update_prefixes;
+extern struct list *bgp_debug_bestpath_prefixes;
 extern struct list *bgp_debug_zebra_prefixes;
 
 struct bgp_debug_filter
@@ -93,6 +96,7 @@ struct bgp_debug_filter
 #define BGP_DEBUG_AS4                 0x01
 #define BGP_DEBUG_AS4_SEGMENT         0x02
 
+#define BGP_DEBUG_BESTPATH            0x01
 #define BGP_DEBUG_NEIGHBOR_EVENTS     0x01
 #define BGP_DEBUG_PACKET              0x01
 #define BGP_DEBUG_KEEPALIVE           0x01
@@ -138,6 +142,7 @@ extern int bgp_debug_neighbor_events(struct peer *peer);
 extern int bgp_debug_keepalive(struct peer *peer);
 extern int bgp_debug_update(struct peer *peer, struct prefix *p,
                             struct update_group *updgrp, unsigned int inbound);
+extern int bgp_debug_bestpath(struct prefix *p);
 extern int bgp_debug_zebra(struct prefix *p);
 
 #endif /* _QUAGGA_BGP_DEBUG_H */
index 8ed928baf36ee5b94b0aa7120748cd5053039b04..14fb49c38b1414e97910771e0fcd22d65a17da37 100644 (file)
@@ -435,8 +435,7 @@ 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);
-  debug = bgp_debug_update(NULL, &rn->p, NULL, 1) ||
-          bgp_debug_update(NULL, &rn->p, NULL, 0);
+  debug = bgp_debug_bestpath(&rn->p);
 
   if (debug)
     prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
index ef26656affba0eb3abd86f6fcdf54d4227b63ff1..5097f0bce666dae20de2ac760d41781e77aca77d 100644 (file)
@@ -319,10 +319,11 @@ 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.  If 'new' is preferable over 'exist' return 1. */
 static int
 bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
-             int *paths_eq, struct bgp_maxpaths_cfg *mpath_cfg)
+             int *paths_eq, struct bgp_maxpaths_cfg *mpath_cfg, int debug,
+              char *pfx_buf)
 {
   struct attr *newattr, *existattr;
   struct attr_extra *newattre, *existattre;
@@ -347,9 +348,19 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
 
   /* 0. Null check. */
   if (new == NULL)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: new is NULL", pfx_buf);
+      return 0;
+    }
+
   if (exist == NULL)
-    return 1;
+    {
+      if (debug)
+        zlog_debug("%s: path %s is the initial bestpath",
+                   pfx_buf, new->peer->host);
+      return 1;
+    }
 
   newattr = new->attr;
   existattr = exist->attr;
@@ -365,9 +376,22 @@ 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to weight %d > %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_weight,
+                   exist_weight);
+      return 1;
+    }
+
   if (new_weight < exist_weight)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to weight %d < %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_weight,
+                   exist_weight);
+      return 0;
+    }
 
   /* 2. Local preference check. */
   new_pref = exist_pref = bgp->default_local_pref;
@@ -378,9 +402,22 @@ 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to localpref %d > %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_pref,
+                   exist_pref);
+      return 1;
+    }
+
   if (new_pref < exist_pref)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to localpref %d < %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_pref,
+                   exist_pref);
+      return 0;
+    }
 
   /* 3. Local route check. We prefer:
    *  - BGP_ROUTE_STATIC
@@ -388,9 +425,20 @@ 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to preferred BGP_ROUTE type",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 1;
+    }
+
   if (! (exist->sub_type == BGP_ROUTE_NORMAL))
-     return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to preferred BGP_ROUTE type",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 0;
+    }
 
   /* 4. AS path length check. */
   if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
@@ -406,26 +454,67 @@ 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;
+            {
+              if (debug)
+                zlog_debug("%s: path %s wins over path %s due to aspath (with confeds) hopcount %d < %d",
+                           pfx_buf, new->peer->host, exist->peer->host,
+                           aspath_hops, (exist_hops + exist_confeds));
+             return 1;
+            }
+
          if ( aspath_hops > (exist_hops + exist_confeds))
-           return 0;
+            {
+              if (debug)
+                zlog_debug("%s: path %s loses to path %s due to aspath (with confeds) hopcount %d > %d",
+                           pfx_buf, new->peer->host, exist->peer->host,
+                           aspath_hops, (exist_hops + exist_confeds));
+             return 0;
+            }
        }
       else
        {
          int newhops = aspath_count_hops (newattr->aspath);
          
          if (newhops < exist_hops)
-           return 1;
+            {
+              if (debug)
+                zlog_debug("%s: path %s wins over path %s due to aspath hopcount %d < %d",
+                           pfx_buf, new->peer->host, exist->peer->host,
+                           newhops, exist_hops);
+             return 1;
+            }
+
           if (newhops > exist_hops)
-           return 0;
+            {
+              if (debug)
+                zlog_debug("%s: path %s loses to path %s due to aspath hopcount %d > %d",
+                           pfx_buf, new->peer->host, exist->peer->host,
+                           newhops, exist_hops);
+             return 0;
+            }
        }
     }
 
   /* 5. Origin check. */
   if (newattr->origin < existattr->origin)
-    return 1;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to ORIGIN %s < %s",
+                   pfx_buf, new->peer->host, exist->peer->host,
+                   bgp_origin_long_str[newattr->origin],
+                   bgp_origin_long_str[existattr->origin]);
+      return 1;
+    }
+
   if (newattr->origin > existattr->origin)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to ORIGIN %s > %s",
+                   pfx_buf, new->peer->host, exist->peer->host,
+                   bgp_origin_long_str[newattr->origin],
+                   bgp_origin_long_str[existattr->origin]);
+      return 0;
+    }
 
   /* 6. MED check. */
   internal_as_route = (aspath_count_hops (newattr->aspath) == 0
@@ -446,9 +535,22 @@ 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;
+        {
+          if (debug)
+            zlog_debug("%s: path %s wins over path %s due to MED %d < %d",
+                       pfx_buf, new->peer->host, exist->peer->host, new_med,
+                       exist_med);
+         return 1;
+        }
+
       if (new_med > exist_med)
-       return 0;
+        {
+          if (debug)
+            zlog_debug("%s: path %s loses to path %s due to MED %d > %d",
+                       pfx_buf, new->peer->host, exist->peer->host, new_med,
+                       exist_med);
+         return 0;
+        }
     }
 
   /* 7. Peer type check. */
@@ -457,10 +559,21 @@ 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to eBGP peer > iBGP peeer",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 1;
+    }
+
   if (exist_sort == BGP_PEER_EBGP
       && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED))
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to iBGP peer < eBGP peeer",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 0;
+    }
 
   /* 8. IGP metric check. */
   newm = existm = 0;
@@ -471,9 +584,20 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
     existm = exist->extra->igpmetric;
 
   if (newm < existm)
-    ret = 1;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to IGP metric %d < %d",
+                   pfx_buf, new->peer->host, exist->peer->host, newm, existm);
+      ret = 1;
+    }
+
   if (newm > existm)
-    ret = 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to IGP metric %d > %d",
+                   pfx_buf, new->peer->host, exist->peer->host, newm, existm);
+      ret = 0;
+    }
 
   /* 8.1. Same IGP metric. Compare the cluster list length as
      representative of IGP hops metric. Rewrite the metric value
@@ -488,10 +612,24 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
        {
          newm = BGP_CLUSTER_LIST_LENGTH(new->attr);
          existm = BGP_CLUSTER_LIST_LENGTH(exist->attr);
+
          if (newm < existm)
-           ret = 1;
+            {
+              if (debug)
+                zlog_debug("%s: path %s wins over path %s due to CLUSTER_LIST length %d < %d",
+                           pfx_buf, new->peer->host, exist->peer->host, newm,
+                           existm);
+             ret = 1;
+            }
+
          if (newm > existm)
-           ret = 0;
+            {
+              if (debug)
+                zlog_debug("%s: path %s loses to path %s due to CLUSTER_LIST length %d > %d",
+                           pfx_buf, new->peer->host, exist->peer->host, newm,
+                           existm);
+             ret = 0;
+            }
        }
     }
 
@@ -510,14 +648,30 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist,
           * array.
           */
          *paths_eq = 1;
+
+          if (debug)
+            zlog_debug("%s: path %s and path %s are equal via multipath-relax",
+                       pfx_buf, new->peer->host, exist->peer->host);
         }
       else if (new->peer->sort == BGP_PEER_IBGP)
        {
          if (aspath_cmp (new->attr->aspath, exist->attr->aspath))
-           *paths_eq = 1;
+            {
+             *paths_eq = 1;
+
+              if (debug)
+                zlog_debug("%s: path %s and path %s are equal via matching aspaths",
+                           pfx_buf, new->peer->host, exist->peer->host);
+            }
        }
       else if (new->peer->as == exist->peer->as)
-       *paths_eq = 1;
+        {
+         *paths_eq = 1;
+
+          if (debug)
+            zlog_debug("%s: path %s and path %s are equal via same remote-as",
+                       pfx_buf, new->peer->host, exist->peer->host);
+        }
     }
   else
     {
@@ -537,9 +691,20 @@ 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;
+        {
+          if (debug)
+              zlog_debug("%s: path %s wins over path %s due to oldest external",
+                         pfx_buf, new->peer->host, exist->peer->host);
+         return 1;
+        }
+
       if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED))
-       return 0;
+        {
+          if (debug)
+              zlog_debug("%s: path %s loses to path %s due to oldest external",
+                         pfx_buf, new->peer->host, exist->peer->host);
+         return 0;
+        }
     }
 
   /* 11. Router-ID comparision. */
@@ -557,34 +722,84 @@ 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to Router-ID comparison",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 1;
+    }
+
   if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr))
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to Router-ID comparison",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 0;
+    }
 
   /* 12. Cluster length comparision. */
   new_cluster = BGP_CLUSTER_LIST_LENGTH(new->attr);
   exist_cluster = BGP_CLUSTER_LIST_LENGTH(exist->attr);
 
   if (new_cluster < exist_cluster)
-    return 1;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to CLUSTER_LIST length %d < %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_cluster,
+                   exist_cluster);
+      return 1;
+    }
+
   if (new_cluster > exist_cluster)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to CLUSTER_LIST length %d > %d",
+                   pfx_buf, new->peer->host, exist->peer->host, new_cluster,
+                   exist_cluster);
+      return 0;
+    }
 
   /* 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;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to latter path being STALE",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 1;
+    }
+
   if (CHECK_FLAG (new->flags, BGP_INFO_STALE))
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to former path being STALE",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 0;
+    }
 
   ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote);
 
   if (ret == 1)
-    return 0;
+    {
+      if (debug)
+        zlog_debug("%s: path %s loses to path %s due to Neighor IP comparison",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 0;
+    }
+
   if (ret == -1)
-    return 1;
+    {
+      if (debug)
+        zlog_debug("%s: path %s wins over path %s due to Neighor IP comparison",
+                   pfx_buf, new->peer->host, exist->peer->host);
+      return 1;
+    }
+
+  if (debug)
+    zlog_debug("%s: path %s wins over path %s due to nothing left to compare",
+               pfx_buf, new->peer->host, exist->peer->host);
 
   return 1;
 }
@@ -1974,14 +2189,20 @@ 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 paths_eq, do_mpath, debug;
   struct list mp_list;
   char buf[INET6_BUFSIZ];
+  char pfx_buf[INET6_ADDRSTRLEN];
 
   bgp_mp_list_init (&mp_list);
   do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS ||
              mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS);
 
+  debug = bgp_debug_bestpath(&rn->p);
+
+  if (debug)
+    prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
+
   /* bgp deterministic-med */
   new_select = NULL;
   if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
@@ -2017,7 +2238,7 @@ 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,
-                                   mpath_cfg))
+                                   mpath_cfg, debug, pfx_buf))
                    {
                      bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
                      new_select = ri2;
@@ -2065,7 +2286,7 @@ 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, mpath_cfg))
+      if (bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, debug, pfx_buf))
        {
          new_select = ri;
        }
@@ -2076,10 +2297,17 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
    */
   if (do_mpath && new_select)
     {
+      if (debug)
+        zlog_debug("%s: path %s is the bestpath, now find multipaths",
+                   pfx_buf, new_select->peer->host);
+
       for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri)
         {
           if (ri == new_select)
             {
+              if (debug)
+                zlog_debug("%s: path %s is the bestpath, add to the multipath list",
+                           pfx_buf, ri->peer->host);
              bgp_mp_list_add (&mp_list, ri);
               continue;
             }
@@ -2097,10 +2325,13 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
               && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED)))
              continue;
 
-          bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg);
+          bgp_info_cmp (bgp, ri, new_select, &paths_eq, mpath_cfg, debug, pfx_buf);
 
           if (paths_eq)
             {
+              if (debug)
+                zlog_debug("%s: %s path is equivalent to the bestpath, add to the multipath list",
+                           pfx_buf, ri->peer->host);
              bgp_mp_list_add (&mp_list, ri);
             }
         }