]> git.proxmox.com Git - mirror_frr.git/commitdiff
BGP: Implement "neighbor x.x.x.x addpath-tx-bestpath-per-AS"
authorDaniel Walton <dwalton@cumulusnetworks.com>
Fri, 6 Nov 2015 16:34:41 +0000 (16:34 +0000)
committerDaniel Walton <dwalton@cumulusnetworks.com>
Fri, 6 Nov 2015 16:34:41 +0000 (16:34 +0000)
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Ticket: CM-8114

bgpd/bgp_aspath.c
bgpd/bgp_aspath.h
bgpd/bgp_open.c
bgpd/bgp_route.c
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h

index c9a6f3fd9efb71adb1daef90a05b87df4f3ad68f..f4d7c4aad8582653193d5f43328bd504fc70dec0 100644 (file)
@@ -1147,6 +1147,15 @@ aspath_firstas_check (struct aspath *aspath, as_t asno)
   return 0;
 }
 
+int
+aspath_get_firstas (struct aspath *aspath)
+{
+  if (aspath == NULL || aspath->segments == NULL)
+    return 0;
+
+  return aspath->segments->as[0];
+}
+
 /* AS path loop check.  If aspath contains asno then return >= 1. */
 int
 aspath_loop_check (struct aspath *aspath, as_t asno)
index faf3bc8eaf21b86445887df7f7639326c12d6817..e4c781385dfbd4cd24a4469214bc27c66e47860b 100644 (file)
@@ -100,6 +100,7 @@ extern const char *aspath_print (struct aspath *);
 extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *);
 extern void aspath_print_all_vty (struct vty *);
 extern unsigned int aspath_key_make (void *);
+extern int aspath_get_firstas (struct aspath *);
 extern int aspath_loop_check (struct aspath *, as_t);
 extern int aspath_private_as_check (struct aspath *);
 extern int aspath_single_asn_check (struct aspath *, as_t asn);
index 2a168899f78df2c39a5b1c04d135a2cb0f994d36..d7a828b0237cb0e5772f243b39d3f869e13b717c 100644 (file)
@@ -1316,7 +1316,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)
 
           /* Only advertise addpath TX if a feature that will use it is
            * configured */
-          if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+          if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS) ||
+              CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
             adv_addpath_tx = 1;
         }
 
index 6c7a24239402cc5111e75b6b2038d2cbbe9aae4c..bb40b4ed47e5ac23a03caeba5a6b49ae7a081100 100644 (file)
@@ -1235,6 +1235,16 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
       return 0;
     }
 
+  /* If this is not the bestpath then check to see if there is an enabled addpath
+   * feature that requires us to advertise it */
+  if (! CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+    {
+      if (! bgp_addpath_tx_path(peer, afi, safi, ri))
+        {
+          return 0;
+        }
+    }
+
   /* Aggregate-address suppress check. */
   if (ri->extra && ri->extra->suppress)
     if (! UNSUPPRESS_MAP_NAME (filter))
@@ -1782,50 +1792,64 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
   /* bgp deterministic-med */
   new_select = NULL;
   if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
-    for (ri1 = rn->info; ri1; ri1 = ri1->next)
-      {
-       if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
-         continue;
-       if (BGP_INFO_HOLDDOWN (ri1))
-         continue;
-        if (ri1->peer && ri1->peer != bgp->peer_self)
-          if (ri1->peer->status != Established)
+    {
+
+      /* Clear BGP_INFO_DMED_SELECTED for all paths */
+      for (ri1 = rn->info; ri1; ri1 = ri1->next)
+        bgp_info_unset_flag (rn, ri1, BGP_INFO_DMED_SELECTED);
+
+      for (ri1 = rn->info; ri1; ri1 = ri1->next)
+        {
+          if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
             continue;
+          if (BGP_INFO_HOLDDOWN (ri1))
+            continue;
+          if (ri1->peer && ri1->peer != bgp->peer_self)
+            if (ri1->peer->status != Established)
+              continue;
 
-       new_select = ri1;
-       old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL;
-       if (ri1->next)
-         for (ri2 = ri1->next; ri2; ri2 = ri2->next)
-           {
-             if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
-               continue;
-             if (BGP_INFO_HOLDDOWN (ri2))
-               continue;
-              if (ri2->peer &&
-                  ri2->peer != bgp->peer_self &&
-                  !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT))
-                if (ri2->peer->status != Established)
-                  continue;
+          new_select = ri1;
+          old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL;
+          if (ri1->next)
+            {
+              for (ri2 = ri1->next; ri2; ri2 = ri2->next)
+                {
+                  if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
+                    continue;
+                  if (BGP_INFO_HOLDDOWN (ri2))
+                    continue;
+                  if (ri2->peer &&
+                      ri2->peer != bgp->peer_self &&
+                      !CHECK_FLAG (ri2->peer->sflags, PEER_STATUS_NSF_WAIT))
+                    if (ri2->peer->status != Established)
+                      continue;
 
-             if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
-                 || aspath_cmp_left_confed (ri1->attr->aspath,
-                                            ri2->attr->aspath))
-               {
-                 if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
-                   old_select = ri2;
-                 if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq,
-                                   mpath_cfg, debug, pfx_buf))
-                   {
-                     bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
-                     new_select = ri2;
-                   }
+                  if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
+                      || aspath_cmp_left_confed (ri1->attr->aspath,
+                                                 ri2->attr->aspath))
+                    {
+                      if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
+                        old_select = ri2;
+                      if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq,
+                                        mpath_cfg, debug, pfx_buf))
+                        {
+                          bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
+                          new_select = ri2;
+                        }
 
-                 bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
-               }
-           }
-       bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
-       bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
-      }
+                      bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
+                    }
+                }
+            }
+          bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
+          bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
+
+          if (debug)
+            zlog_debug("%s: path %s is the bestpath from AS %d",
+                       pfx_buf, new_select->peer->host,
+                       aspath_get_firstas(new_select->attr->aspath));
+        }
+    }
 
   /* Check old selected route and new selected route. */
   old_select = NULL;
@@ -1859,8 +1883,8 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
          bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK);
          continue;
         }
+
       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, debug, pfx_buf))
        {
@@ -7311,6 +7335,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
   struct peer *peer;
   int addpath_capable;
   int has_adj;
+  int first_as;
 
   if (json_paths)
     {
@@ -7733,18 +7758,41 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
            vty_out (vty, ", multipath");
         }
 
+      // Mark the bestpath(s)
+      if (CHECK_FLAG (binfo->flags, BGP_INFO_DMED_SELECTED))
+        {
+          first_as = aspath_get_firstas(attr->aspath);
+
+          if (json_paths)
+            {
+              if (!json_bestpath)
+                json_bestpath = json_object_new_object();
+              json_object_int_add(json_bestpath, "bestpathFromAs", first_as);
+            }
+          else
+            {
+              if (first_as)
+               vty_out (vty, ", bestpath-from-AS %d", first_as);
+              else
+               vty_out (vty, ", bestpath-from-AS Local");
+            }
+        }
+
       if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
         {
           if (json_paths)
             {
-              json_bestpath = json_object_new_object();
+              if (!json_bestpath)
+                json_bestpath = json_object_new_object();
               json_object_boolean_true_add(json_bestpath, "overall");
-              json_object_object_add(json_path, "bestpath", json_bestpath);
             }
           else
            vty_out (vty, ", best");
         }
 
+      if (json_bestpath)
+        json_object_object_add(json_path, "bestpath", json_bestpath);
+
       if (!json_paths)
         vty_out (vty, "%s", VTY_NEWLINE);
          
index c0f0c20b7c47715fe7783a34a2506a70738c4cab..cfb3c79767155fa96472e9395e32cbbbc6b35bad 100644 (file)
@@ -1955,9 +1955,28 @@ update_group_clear_update_dbg (struct update_group *updgrp, void *arg)
   return UPDWALK_CONTINUE;
 }
 
+/* Return true if we should addpath encode NLRI to this peer */
 int
 bgp_addpath_encode_tx (struct peer *peer, afi_t afi, safi_t safi)
 {
   return (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV) &&
           CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV));
 }
+
+/*
+ * Return true if this is a path we should advertise due to a
+ * configured addpath-tx knob
+ */
+int
+bgp_addpath_tx_path (struct peer *peer, afi_t afi, safi_t safi,
+                 struct bgp_info *ri)
+{
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+    return 1;
+
+  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS) &&
+      CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))
+    return 1;
+
+  return 0;
+}
index 1ca62a0a8399d08357bb0c34af6a2a1c0c39f382..427168db5a6ca21dd3b5adc4fd088e593a383378 100644 (file)
@@ -50,6 +50,7 @@
                              PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
                              PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | \
                               PEER_FLAG_ADDPATH_TX_ALL_PATHS | \
+                              PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS | \
                              PEER_FLAG_AS_OVERRIDE)
 
 #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
@@ -480,6 +481,8 @@ update_group_clear_update_dbg (struct update_group *updgrp, void *arg);
 
 extern void update_bgp_group_free(struct bgp *bgp);
 extern int bgp_addpath_encode_tx (struct peer *peer, afi_t afi, safi_t safi);
+extern int bgp_addpath_tx_path (struct peer *peer, afi_t afi, safi_t safi,
+                                struct bgp_info *ri);
 
 /*
  * Inline functions
index 493948e79ad386be6ab56500ebda4542717cd00e..cc2fb8afd580a947fc4f3c561a4f4426008293c6 100644 (file)
@@ -155,16 +155,17 @@ group_announce_route_walkcb (struct update_group *updgrp, void *arg)
                     }
                 }
 
-              if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+              for (ri = ctx->rn->info; ri; ri = ri->next)
                 {
-                  for (ri = ctx->rn->info; ri; ri = ri->next)
-                    {
-                      if (ri == ctx->ri)
-                          continue;
-                      subgroup_process_announce_selected (subgrp, ri, ctx->rn, ri->addpath_tx_id);
-                    }
+                  /* Skip the bestpath for now */
+                  if (ri == ctx->ri)
+                    continue;
+
+                  subgroup_process_announce_selected (subgrp, ri, ctx->rn, ri->addpath_tx_id);
                 }
 
+              /* Process the bestpath last so the "show ip bgp neighbor x.x.x.x advertised"
+               * output shows the attributes from the bestpath */
               if (ctx->ri)
                 subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn, ctx->ri->addpath_tx_id);
             }
@@ -613,8 +614,7 @@ subgroup_announce_table (struct update_subgroup *subgrp,
     for (ri = rn->info; ri; ri = ri->next)
 
       if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) ||
-          (addpath_capable &&
-           CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS)))
+          (addpath_capable && bgp_addpath_tx_path(peer, afi, safi, ri)))
        {
          if (!rsclient
              && subgroup_announce_check (ri, subgrp, &rn->p, &attr))
index c021e8297565663a661d28422c20c2f674607660..753f529aad699b0ad85ba58e8961ad7091a6aaa2 100644 (file)
@@ -289,28 +289,6 @@ enum clear_sort
   clear_as
 };
 
-/* Force a bestpath recalculation for all prefixes.  This is used
- * when 'bgp bestpath' commands are entered.
- */
-static void
-bgp_recalculate_all_bestpaths (struct bgp *bgp)
-{
-  afi_t afi;
-  safi_t safi;
-  struct bgp_node *rn;
-
-  for (afi = AFI_IP; afi < AFI_MAX; afi++)
-    {
-      for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
-        {
-          for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn))
-            {
-              bgp_process (bgp, rn, afi, safi);
-            }
-        }
-    }
-}
-
 static void
 bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi,
                     safi_t safi, int error)
@@ -1655,13 +1633,43 @@ DEFUN (no_bgp_deterministic_med,
        "Pick the best-MED path among paths advertised from the neighboring AS\n")
 {
   struct bgp *bgp;
+  int bestpath_per_as_used;
+  afi_t afi;
+  safi_t safi;
+  struct peer *peer;
+  struct listnode *node, *nnode;
 
   bgp = vty->index;
 
   if (bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED))
     {
-      bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED);
-      bgp_recalculate_all_bestpaths (bgp);
+      bestpath_per_as_used = 0;
+
+      for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+        {
+          for (afi = AFI_IP; afi < AFI_MAX; afi++)
+            for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+              if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+                {
+                  bestpath_per_as_used = 1;
+                  break;
+                }
+
+          if (bestpath_per_as_used)
+            break;
+        }
+
+      if (bestpath_per_as_used)
+        {
+          vty_out (vty, "bgp deterministic-med cannot be disabled while addpath-tx-bestpath-per-AS is in use%s",
+                   VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      else
+        {
+          bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED);
+          bgp_recalculate_all_bestpaths (bgp);
+        }
     }
 
   return CMD_SUCCESS;
@@ -5803,6 +5811,38 @@ DEFUN (no_neighbor_addpath_tx_all_paths,
                                 PEER_FLAG_ADDPATH_TX_ALL_PATHS);
 }
 
+DEFUN (neighbor_addpath_tx_bestpath_per_as,
+       neighbor_addpath_tx_bestpath_per_as_cmd,
+       NEIGHBOR_CMD2 "addpath-tx-bestpath-per-AS",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Use addpath to advertise the bestpath per each neighboring AS\n")
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+                              bgp_node_safi (vty),
+                              PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
+}
+
+DEFUN (no_neighbor_addpath_tx_bestpath_per_as,
+       no_neighbor_addpath_tx_bestpath_per_as_cmd,
+       NO_NEIGHBOR_CMD2 "addpath-tx-bestpath-per-AS",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Use addpath to advertise the bestpath per each neighboring AS\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS);
+}
+
+
 /* Address family configuration.  */
 DEFUN (address_family_ipv4,
        address_family_ipv4_cmd,
@@ -9282,6 +9322,9 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
       if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
         json_object_boolean_true_add(json_addr, "addpathTxAllPaths");
 
+      if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+        json_object_boolean_true_add(json_addr, "addpathTxBestpathPerAS");
+
       if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
         json_object_string_add(json_addr, "overrideASNsInOutboundUpdates", "ifAspathEqualRemoteAs");
 
@@ -9472,6 +9515,9 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
       if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
         vty_out (vty, "  Advertise all paths via addpath%s", VTY_NEWLINE);
 
+      if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+        vty_out (vty, "  Advertise bestpath per AS via addpath%s", VTY_NEWLINE);
+
       if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_OVERRIDE))
         vty_out (vty, "  Override ASNs in outbound updates if aspath equals remote-as%s", VTY_NEWLINE);
 
@@ -13223,6 +13269,20 @@ bgp_vty_init (void)
   install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
 
+  /* "neighbor addpath-tx-bestpath-per-AS" commands.*/
+  install_element (BGP_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_bestpath_per_as_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd);
+
   /* "neighbor passive" commands. */
   install_element (BGP_NODE, &neighbor_passive_cmd);
   install_element (BGP_NODE, &no_neighbor_passive_cmd);
index 7b76345147cad43d6cc4d01d819beb5957013450..4e026d8d4564f7f9169427a9a9d3c563180b76d3 100644 (file)
@@ -1362,6 +1362,28 @@ bgp_peer_conf_if_to_su_update (struct peer *peer)
   hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
 }
 
+/* Force a bestpath recalculation for all prefixes.  This is used
+ * when 'bgp bestpath' commands are entered.
+ */
+void
+bgp_recalculate_all_bestpaths (struct bgp *bgp)
+{
+  afi_t afi;
+  safi_t safi;
+  struct bgp_node *rn;
+
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    {
+      for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+        {
+          for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn))
+            {
+              bgp_process (bgp, rn, afi, safi);
+            }
+        }
+    }
+}
+
 /* Create new BGP peer.  */
 struct peer *
 peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
@@ -3484,6 +3506,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
     { PEER_FLAG_AS_OVERRIDE,              1, peer_change_reset_out },
     { PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,1, peer_change_reset_out },
     { PEER_FLAG_ADDPATH_TX_ALL_PATHS,     1, peer_change_reset },
+    { PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, 1, peer_change_reset },
     { 0, 0, 0 }
   };
 
@@ -3792,7 +3815,7 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
     }
 
   /* Track if addpath TX is in use */
-  if (flag & PEER_FLAG_ADDPATH_TX_ALL_PATHS)
+  if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS|PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
     {
       bgp = peer->bgp;
       addpath_tx_used = 0;
@@ -3800,12 +3823,25 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
       if (set)
         {
           addpath_tx_used = 1;
+
+          if (flag & PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)
+            {
+              if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+                {
+                  zlog_warn("%s: enabling bgp deterministic-med, this is required"\
+                            " for addpath-tx-bestpath-per-AS",
+                            peer->host);
+                  bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
+                  bgp_recalculate_all_bestpaths (bgp);
+                }
+            }
         }
       else
         {
           for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, tmp_peer))
             {
-              if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+              if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS) ||
+                  CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
                 {
                   addpath_tx_used = 1;
                   break;
@@ -6551,8 +6587,10 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
 
   /* addpath TX knobs */
   if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_ALL_PATHS))
-    vty_out (vty, "  neighbor %s addpath-tx-all-paths%s", addr,
-            VTY_NEWLINE);
+    vty_out (vty, "  neighbor %s addpath-tx-all-paths%s", addr, VTY_NEWLINE);
+
+  if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
+    vty_out (vty, "  neighbor %s addpath-tx-bestpath-per-AS%s", addr, VTY_NEWLINE);
 
   /* ORF capability.  */
   if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) ||
index 7ed8176b1c952622d2d6a9e33044e95f45b01650..851527b3bd84784cec0995b2f96ec4af4a07a867 100644 (file)
@@ -654,6 +654,7 @@ struct peer
 #define PEER_FLAG_AS_OVERRIDE               (1 << 20) /* as-override */
 #define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1 << 21) /* remove-private-as all replace-as */
 #define PEER_FLAG_ADDPATH_TX_ALL_PATHS      (1 << 22) /* addpath-tx-all-paths */
+#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
 
   /* MD5 password */
   char *password;
@@ -1152,6 +1153,7 @@ extern struct peer *peer_unlock_with_caller(const char *, struct peer *);
 extern bgp_peer_sort_t peer_sort (struct peer *peer);
 extern int peer_active (struct peer *);
 extern int peer_active_nego (struct peer *);
+extern void bgp_recalculate_all_bestpaths (struct bgp *bgp);
 extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
                                 as_t, as_t, int, afi_t, safi_t);
 extern struct peer *peer_create_accept (struct bgp *);