]> git.puffer.fish Git - mirror/frr.git/commitdiff
BGP: support for addpath TX
authorDaniel Walton <dwalton@cumulusnetworks.com>
Thu, 5 Nov 2015 17:29:43 +0000 (17:29 +0000)
committerDaniel Walton <dwalton@cumulusnetworks.com>
Thu, 5 Nov 2015 17:29:43 +0000 (17:29 +0000)
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Vivek Venkataraman <vivek@cumulusnetworks.com
Ticket: CM-8014

This implements addpath TX with the first feature to use it
being "neighbor x.x.x.x addpath-tx-all-paths".

One change to show output is 'show ip bgp x.x.x.x'.  If no addpath-tx
features are configured for any peers then everything looks the same
as it is today in that "Advertised to" is at the top and refers to
which peers the bestpath was advertise to.

root@superm-redxp-05[quagga-stash5]# vtysh -c 'show ip bgp 1.1.1.1'
BGP routing table entry for 1.1.1.1/32
Paths: (6 available, best #6, table Default-IP-Routing-Table)
  Advertised to non peer-group peers:
  r1(10.0.0.1) r2(10.0.0.2) r3(10.0.0.3) r4(10.0.0.4) r5(10.0.0.5) r6(10.0.0.6) r8(10.0.0.8)
  Local, (Received from a RR-client)
    12.12.12.12 (metric 20) from r2(10.0.0.2) (10.0.0.2)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 8
      Last update: Fri Oct 30 18:26:44 2015
[snip]

but once you enable an addpath feature we must display "Advertised to" on a path-by-path basis:

superm-redxp-05# show ip bgp 1.1.1.1/32
BGP routing table entry for 1.1.1.1/32
Paths: (6 available, best #6, table Default-IP-Routing-Table)
  Local, (Received from a RR-client)
    12.12.12.12 (metric 20) from r2(10.0.0.2) (10.0.0.2)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 8
      Advertised to: r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:44 2015

  Local, (Received from a RR-client)
    34.34.34.34 (metric 20) from r3(10.0.0.3) (10.0.0.3)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 7
      Advertised to: r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:39 2015

  Local, (Received from a RR-client)
    56.56.56.56 (metric 20) from r6(10.0.0.6) (10.0.0.6)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 6
      Advertised to: r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:39 2015

  Local, (Received from a RR-client)
    56.56.56.56 (metric 20) from r5(10.0.0.5) (10.0.0.5)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 5
      Advertised to: r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:39 2015

  Local, (Received from a RR-client)
    34.34.34.34 (metric 20) from r4(10.0.0.4) (10.0.0.4)
      Origin IGP, metric 0, localpref 100, valid, internal
      AddPath ID: RX 0, TX 4
      Advertised to: r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:39 2015

  Local, (Received from a RR-client)
    12.12.12.12 (metric 20) from r1(10.0.0.1) (10.0.0.1)
      Origin IGP, metric 0, localpref 100, valid, internal, best
      AddPath ID: RX 0, TX 3
      Advertised to: r1(10.0.0.1) r2(10.0.0.2) r3(10.0.0.3) r4(10.0.0.4) r5(10.0.0.5) r6(10.0.0.6) r8(10.0.0.8)
      Last update: Fri Oct 30 18:26:34 2015

superm-redxp-05#

18 files changed:
bgpd/bgp_advertise.c
bgpd/bgp_advertise.h
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_open.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/stream.c
lib/stream.h

index 70d878739ca668593dc898e0ff882e95a1c59e66..73b2619c263d44f69dc0a1116e0cd55c2bd91462 100644 (file)
@@ -155,30 +155,29 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
     }
 }
 
-struct bgp_adj_out *
-bgp_adj_peer_lookup (struct peer *peer, struct bgp_node *rn)
-{
-  struct bgp_adj_out *adj;
-  struct peer_af *paf;
-
-  for (adj = rn->adj_out; adj; adj = adj->next)
-    SUBGRP_FOREACH_PEER(adj->subgroup, paf)
-      if (paf->peer == peer)
-       return adj;
-  return NULL;
-}
-
 int
-bgp_adj_out_lookup (struct peer *peer, struct prefix *p,
-                   afi_t afi, safi_t safi, struct bgp_node *rn)
+bgp_adj_out_lookup (struct peer *peer, struct bgp_node *rn,
+                    u_int32_t addpath_tx_id)
 {
   struct bgp_adj_out *adj;
   struct peer_af *paf;
+  afi_t afi;
+  safi_t safi;
+  int addpath_capable;
 
   for (adj = rn->adj_out; adj; adj = adj->next)
     SUBGRP_FOREACH_PEER(adj->subgroup, paf)
       if (paf->peer == peer)
        {
+          afi = SUBGRP_AFI (adj->subgroup);
+          safi = SUBGRP_SAFI (adj->subgroup);
+          addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
+
+          /* Match on a specific addpath_tx_id if we are using addpath for this
+           * peer and if an addpath_tx_id was specified */
+          if (addpath_capable && addpath_tx_id && adj->addpath_tx_id != addpath_tx_id)
+            continue;
+
          return (adj->adv
                  ? (adj->adv->baa ? 1 : 0)
                  : (adj->attr ? 1 : 0));
index d5b737b9edd4cc5d95eecdc35d500eb82e2dc528..ae6e6bd14770a17674771a2946b0621808d5370d 100644 (file)
@@ -82,6 +82,8 @@ struct bgp_adj_out
   /* Prefix information.  */
   struct bgp_node *rn;
 
+  u_int32_t addpath_tx_id;
+
   /* Advertised attribute.  */
   struct attr *attr;
 
@@ -168,9 +170,7 @@ struct bgp_synchronize
   ? NULL : (F)->next)
 
 /* Prototypes.  */
-extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t,
-                       struct bgp_node *);
-
+extern int bgp_adj_out_lookup (struct peer *, struct bgp_node *, u_int32_t);
 extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *, u_int32_t);
 extern void bgp_adj_in_unset (struct bgp_node *, struct peer *, u_int32_t);
 extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *);
@@ -191,7 +191,5 @@ bgp_advertise_delete (struct bgp_advertise_attr *baa,
                      struct bgp_advertise *adv);
 extern void
 bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa);
-extern struct bgp_adj_out *
-bgp_adj_peer_lookup (struct peer *peer, struct bgp_node *rn);
 
 #endif /* _QUAGGA_BGP_ADVERTISE_H */
index 3a031e0db35c90aeeb2bedd3016a47b68ecf632e..d37fa1e79a7b93468464948ff37ecee9f54cd20e 100644 (file)
@@ -2140,8 +2140,6 @@ bgp_attr_check (struct peer *peer, struct attr *attr, bgp_size_t nlri_len)
   return BGP_ATTR_PARSE_PROCEED;
 }
 
-int stream_put_prefix (struct stream *, struct prefix *);
-
 size_t
 bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
                         struct bpacket_attr_vec_arr *vecarr,
@@ -2213,11 +2211,16 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
 void
 bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
                          struct prefix *p, struct prefix_rd *prd,
-                         u_char *tag)
+                          u_char *tag, int addpath_encode,
+                          u_int32_t addpath_tx_id)
 {
   switch (safi)
     {
     case SAFI_MPLS_VPN:
+      /* addpath TX ID */
+      if (addpath_encode)
+        stream_putl(s, addpath_tx_id);
+
       /* Tag, RD, Prefix write. */
       stream_putc (s, p->prefixlen + 88);
       stream_put (s, tag, 3);
@@ -2226,7 +2229,7 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
       break;
     default:
       /* Prefix write. */
-      stream_put_prefix (s, p);
+      stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
       break;
     }
 }
@@ -2245,7 +2248,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
                      struct stream *s, struct attr *attr,
                      struct bpacket_attr_vec_arr *vecarr,
                      struct prefix *p, afi_t afi, safi_t safi,
-                     struct peer *from, struct prefix_rd *prd, u_char *tag)
+                     struct peer *from, struct prefix_rd *prd, u_char *tag,
+                      int addpath_encode,
+                      u_int32_t addpath_tx_id)
 {
   size_t cp;
   size_t aspath_sizep;
@@ -2267,7 +2272,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
       mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi,
                                     (peer_cap_enhe(peer) ? AFI_IP6 : afi),
                                     vecarr, attr);
-      bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
+      bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag,
+                               addpath_encode, addpath_tx_id);
       bgp_packet_mpattr_end(s, mpattrlen_pos);
     }
 
@@ -2635,17 +2641,22 @@ bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
 void
 bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
                             afi_t afi, safi_t safi, struct prefix_rd *prd,
-                            u_char *tag)
+                            u_char *tag, int addpath_encode,
+                             u_int32_t addpath_tx_id)
 {
   if (safi == SAFI_MPLS_VPN)
     {
+      /* addpath TX ID */
+      if (addpath_encode)
+        stream_putl(s, addpath_tx_id);
+
       stream_putc (s, p->prefixlen + 88);
       stream_put (s, tag, 3);
       stream_put (s, prd->val, 8);
       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
     }
   else
-    stream_put_prefix (s, p);
+    stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
 }
 
 void
@@ -2691,6 +2702,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
   unsigned long len;
   size_t aspath_lenp;
   struct aspath *aspath;
+  int addpath_encode = 0;
+  u_int32_t addpath_tx_id = 0;
 
   /* Remember current pointer. */
   cp = stream_get_endp (s);
@@ -2810,7 +2823,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
       stream_putc(s, 0);
 
       /* Prefix */
-      stream_put_prefix(s, prefix);
+      stream_put_prefix_addpath (s, prefix, addpath_encode, addpath_tx_id);
 
       /* Set MP attribute length. */
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
index a846faf6794bd93819285e44a588fba5ba9a3e99..789422f640f546aa3632f83fe3260e9238d20cc6 100644 (file)
@@ -196,9 +196,9 @@ extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *,
                                        struct bpacket_attr_vec_arr *vecarr,
                                        struct prefix *, afi_t, safi_t,
                                        struct peer *, struct prefix_rd *,
-                                       u_char *);
+                                       u_char *, int, u_int32_t);
 extern void bgp_dump_routes_attr (struct stream *, struct attr *,
-                                 struct prefix *);
+                                  struct prefix *);
 extern int attrhash_cmp (const void *, const void *);
 extern unsigned int attrhash_key_make (void *);
 extern void attr_show_all (struct vty *);
@@ -239,14 +239,15 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
                                      struct attr *attr);
 extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                                     struct prefix *p, struct prefix_rd *prd,
-                                    u_char *tag);
+                                    u_char *tag, int addpath_encode,
+                                     u_int32_t addpath_tx_id);
 extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep);
 
 extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi,
                                          safi_t safi);
 extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
                             afi_t afi, safi_t safi, struct prefix_rd *prd,
-                            u_char *tag);
+                            u_char *tag, int, u_int32_t);
 extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt);
 
 static inline int
index b667c4a2c86c23bb6e8c1685ac6ecc3c96f28408..d3081887c409c05b2e6f161a39d99f7d1ca28f96 100644 (file)
@@ -93,7 +93,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,
   u_char *tagpnt;
   afi_t afi;
   safi_t safi;
-  u_char addpath_encoded;
+  int addpath_encoded;
   u_int32_t addpath_id;
 
   /* Check peer status. */
index e346d7896c2ddb8fb6e282cb7284cef0ef65d7bf..2a168899f78df2c39a5b1c04d135a2cb0f994d36 100644 (file)
@@ -1188,6 +1188,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)
   u_int32_t restart_time;
   u_char afi_safi_count = 0;
   struct utsname names;
+  int adv_addpath_tx = 0;
 
   /* Remember current pointer for Opt Parm Len. */
   cp = stream_get_endp (s);
@@ -1306,13 +1307,18 @@ bgp_open_capability (struct stream *s, struct peer *peer)
     local_as = peer->local_as;
   stream_putl (s, local_as );
 
-  /* AddPath
-   * For now we will only advertise RX support. TX support will be added later.
-   */
+  /* AddPath */
   for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
     for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
       if (peer->afc[afi][safi])
-        afi_safi_count++;
+        {
+          afi_safi_count++;
+
+          /* 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))
+            adv_addpath_tx = 1;
+        }
 
   SET_FLAG (peer->cap, PEER_CAP_ADDPATH_ADV);
   stream_putc (s, BGP_OPEN_OPT_CAP);
@@ -1326,8 +1332,19 @@ bgp_open_capability (struct stream *s, struct peer *peer)
         {
           stream_putw (s, afi);
           stream_putc (s, safi);
-          stream_putc (s, BGP_ADDPATH_RX);
-          SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV);
+
+          if (adv_addpath_tx)
+            {
+              stream_putc (s, BGP_ADDPATH_RX|BGP_ADDPATH_TX);
+              SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV);
+              SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV);
+            }
+          else
+            {
+              stream_putc (s, BGP_ADDPATH_RX);
+              SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV);
+              UNSET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV);
+            }
         }
 
   /* ORF capability. */
index f7336ea2f18002a79bd6d055b6839739c9558a8c..4a99ad4c6c4e366f900632fe1477f611e37b89dd 100644 (file)
@@ -50,8 +50,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_vty.h"
 #include "bgpd/bgp_updgrp.h"
 
-int stream_put_prefix (struct stream *, struct prefix *);
-
 /* Set up BGP packet marker and packet type. */
 int
 bgp_packet_set_marker (struct stream *s, u_char type)
index 820c3cfd9a9daef64cc72cce492d9edf899a6f19..6c7a24239402cc5111e75b6b2038d2cbbe9aae4c 100644 (file)
@@ -1226,6 +1226,15 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
   bgp = SUBGRP_INST(subgrp);
   riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
 
+  /* With addpath we may be asked to TX all kinds of paths so make sure
+   * ri is valid */
+  if (!CHECK_FLAG (ri->flags, BGP_INFO_VALID) ||
+      CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) ||
+      CHECK_FLAG (ri->flags, BGP_INFO_REMOVED))
+    {
+      return 0;
+    }
+
   /* Aggregate-address suppress check. */
   if (ri->extra && ri->extra->suppress)
     if (! UNSUPPRESS_MAP_NAME (filter))
@@ -1917,7 +1926,8 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
 int
 subgroup_process_announce_selected (struct update_subgroup *subgrp,
                                    struct bgp_info *selected,
-                                   struct bgp_node *rn)
+                                   struct bgp_node *rn,
+                                    u_int32_t addpath_tx_id)
 {
   struct prefix *p;
   struct peer *onlypeer;
@@ -1945,20 +1955,37 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp,
       case BGP_TABLE_MAIN:
       /* Announcement to the subgroup.  If the route is filtered,
          withdraw it. */
-       if (selected && subgroup_announce_check(selected, subgrp, p, &attr))
-         bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
-        else
-         bgp_adj_out_unset_subgroup(rn, subgrp, 1);
+        if (selected)
+          {
+            if (subgroup_announce_check(selected, subgrp, p, &attr))
+              bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
+            else
+              bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
+          }
 
+        /* If selected is NULL we must withdraw the path using addpath_tx_id */
+        else
+          {
+            bgp_adj_out_unset_subgroup(rn, subgrp, 1, addpath_tx_id);
+          }
         break;
+
       case BGP_TABLE_RSCLIENT:
         /* Announcement to peer->conf.  If the route is filtered,
            withdraw it. */
-        if (selected &&
-            subgroup_announce_check_rsclient (selected, subgrp, p, &attr))
-          bgp_adj_out_set_subgroup (rn, subgrp, &attr, selected);
+        if (selected)
+          {
+            if (subgroup_announce_check_rsclient(selected, subgrp, p, &attr))
+              bgp_adj_out_set_subgroup(rn, subgrp, &attr, selected);
+            else
+              bgp_adj_out_unset_subgroup(rn, subgrp, 1, selected->addpath_tx_id);
+          }
+
+        /* If selected is NULL we must withdraw the path using addpath_tx_id */
         else
-         bgp_adj_out_unset_subgroup(rn, subgrp, 1);
+          {
+            bgp_adj_out_unset_subgroup(rn, subgrp, 1, addpath_tx_id);
+          }
         break;
     }
 
@@ -2033,7 +2060,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
            subgrp = PAF_SUBGRP(paf);
            if (!subgrp) /* not an established session */
              continue;
-            subgroup_process_announce_selected (subgrp, new_select, rn);
+            subgroup_process_announce_selected (subgrp, new_select, rn, new_select->addpath_tx_id);
           }
     }
   else
@@ -2048,7 +2075,7 @@ bgp_process_rsclient (struct work_queue *wq, void *data)
        }
       paf = peer_af_find(rsclient, afi, safi);
       if (paf && (subgrp = PAF_SUBGRP(paf))) /* if an established session */
-       subgroup_process_announce_selected (subgrp, new_select, rn);
+       subgroup_process_announce_selected (subgrp, new_select, rn, new_select->addpath_tx_id);
     }
 
   if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
@@ -2095,18 +2122,18 @@ bgp_process_main (struct work_queue *wq, void *data)
   new_select = old_and_new.new;
 
   /* Nothing to do. */
-  if (old_select && old_select == new_select && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR))
-    {
-      if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
-        {
-          if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
-             CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
-            bgp_zebra_announce (p, old_select, bgp, afi, safi);
+  if (old_select && old_select == new_select &&
+      !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR) &&
+      !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) &&
+      !bgp->addpath_tx_used[afi][safi])
+    {
+      if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
+          CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
+        bgp_zebra_announce (p, old_select, bgp, afi, safi);
           
-         UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
-          UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
-          return WQ_SUCCESS;
-        }
+      UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
+      UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+      return WQ_SUCCESS;
     }
 
   /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set */
@@ -2157,7 +2184,7 @@ bgp_process_main (struct work_queue *wq, void *data)
        }
     }
     
-  /* Reap old select bgp_info, it it has been removed */
+  /* Reap old select bgp_info, if it has been removed */
   if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED))
     bgp_info_reap (rn, old_select);
   
@@ -2433,6 +2460,7 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a
   new->attr = attr;
   new->uptime = bgp_clock ();
   new->net = rn;
+  new->addpath_tx_id = ++peer->bgp->addpath_tx_id;
   return new;
 }
 
@@ -3032,7 +3060,6 @@ bgp_update_main (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
   /* Addpath ID */
   new->addpath_rx_id = addpath_id;
-  new->addpath_tx_id = 0;
 
   /* Increment prefix */
   bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -3527,17 +3554,6 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
           ain = ain_next;
         }
 
-      /*
-       * Can't do this anymore. adj-outs are not maintained per peer.
-       *
-      for (aout = rn->adj_out; aout; aout = aout->next)
-        if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
-          {
-            bgp_adj_out_remove (rn, aout, peer, afi, safi);
-            bgp_unlock_node (rn);
-            break;
-          }
-      */
       for (ri = rn->info; ri; ri = ri->next)
         if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT)
           {
@@ -3728,6 +3744,13 @@ bgp_reset (void)
   prefix_list_reset ();
 }
 
+static int
+bgp_addpath_encode_rx (struct peer *peer, afi_t afi, safi_t safi)
+{
+  return (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
+          CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+}
+
 /* Parse NLRI stream.  Withdraw NLRI is recognized by NULL attr
    value. */
 int
@@ -3740,7 +3763,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
   int ret;
   afi_t afi;
   safi_t safi;
-  u_char addpath_encoded;
+  int addpath_encoded;
   u_int32_t addpath_id;
 
   /* Check peer status. */
@@ -3752,9 +3775,7 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
   afi = packet->afi;
   safi = packet->safi;
   addpath_id = 0;
-
-  addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
-                     CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+  addpath_encoded = bgp_addpath_encode_rx (peer, afi, safi);
 
   for (; pnt < lim; pnt += psize)
     {
@@ -3856,13 +3877,11 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi, u_char *pnt,
   u_char *end;
   u_char prefixlen;
   int psize;
-  u_char addpath_encoded;
+  int addpath_encoded;
 
   *numpfx = 0;
   end = pnt + length;
-
-  addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) &&
-                     CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV));
+  addpath_encoded = bgp_addpath_encode_rx (peer, afi, safi);
 
   /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for
      syntactic validity.  If the field is syntactically incorrect,
@@ -7212,6 +7231,57 @@ flap_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo,
     vty_out (vty, "%s", VTY_NEWLINE);
 }
 
+static void
+route_vty_out_advertised_to (struct vty *vty, struct peer *peer, int *first,
+                             const char *header, json_object *json_adv_to)
+{
+  char buf1[INET6_ADDRSTRLEN];
+  json_object *json_peer = NULL;
+
+  if (json_adv_to)
+    {
+      /* 'advertised-to' is a dictionary of peers we have advertised this
+       * prefix too.  The key is the peer's IP or swpX, the value is the
+       * hostname if we know it and "" if not.
+       */
+      json_peer = json_object_new_object();
+
+      if (peer->hostname)
+        json_object_string_add(json_peer, "hostname", peer->hostname);
+
+      if (peer->conf_if)
+        json_object_object_add(json_adv_to, peer->conf_if, json_peer);
+      else
+        json_object_object_add(json_adv_to,
+                               sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN),
+                               json_peer);
+    }
+  else
+    {
+      if (*first)
+        {
+          vty_out (vty, "%s", header);
+          *first = 0;
+        }
+
+      if (peer->hostname && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
+        {
+          if (peer->conf_if)
+            vty_out (vty, " %s(%s)", peer->hostname, peer->conf_if);
+          else
+            vty_out (vty, " %s(%s)", peer->hostname,
+                     sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
+        }
+      else
+        {
+          if (peer->conf_if)
+            vty_out (vty, " %s", peer->conf_if);
+          else
+            vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
+        }
+    }
+}
+
 static void
 route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, 
                      struct bgp_info *binfo, afi_t afi, safi_t safi,
@@ -7235,6 +7305,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
   json_object *json_path = NULL;
   json_object *json_peer = NULL;
   json_object *json_string = NULL;
+  json_object *json_adv_to = NULL;
+  int first = 0;
+  struct listnode *node, *nnode;
+  struct peer *peer;
+  int addpath_capable;
+  int has_adj;
 
   if (json_paths)
     {
@@ -7775,6 +7851,45 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
             }
         }
 
+      /* If we used addpath to TX a non-bestpath we need to display
+       * "Advertised to" on a path-by-path basis */
+      if (bgp->addpath_tx_used[afi][safi])
+        {
+          first = 1;
+
+          for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+            {
+              addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
+              has_adj = bgp_adj_out_lookup (peer, binfo->net, binfo->addpath_tx_id);
+
+              if ((addpath_capable && has_adj) ||
+                  (!addpath_capable && has_adj && CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)))
+                {
+                    if (json_path && !json_adv_to)
+                      json_adv_to = json_object_new_object();
+
+                    route_vty_out_advertised_to(vty, peer, &first,
+                                                "      Advertised to:",
+                                                json_adv_to);
+                }
+            }
+
+          if (json_path)
+            {
+              if (json_adv_to)
+                {
+                  json_object_object_add(json_path, "advertisedTo", json_adv_to);
+                }
+            }
+          else
+            {
+              if (!first)
+                {
+                 vty_out (vty, "%s", VTY_NEWLINE);
+                }
+            }
+        }
+
       /* Line 8 display Uptime */
 #ifdef HAVE_CLOCK_MONOTONIC
       tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
@@ -8161,9 +8276,8 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
   int no_export = 0;
   int no_advertise = 0;
   int local_as = 0;
-  int first = 0;
+  int first = 1;
   json_object *json_adv_to = NULL;
-  json_object *json_peer = NULL;
 
   p = &rn->p;
 
@@ -8226,70 +8340,38 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
       vty_out (vty, ")%s", VTY_NEWLINE);
     }
 
-  /* advertised peer */
-  for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+  /* If we are not using addpath then we can display Advertised to and that will
+   * show what peers we advertised the bestpath to.  If we are using addpath
+   * though then we must display Advertised to on a path-by-path basis. */
+  if (!bgp->addpath_tx_used[afi][safi])
     {
-      if (bgp_adj_out_lookup (peer, p, afi, safi, rn))
-       {
-          if (json)
+      for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+        {
+          if (bgp_adj_out_lookup (peer, rn, 0))
             {
-              /* 'advertised-to' is a dictionary of peers we have advertised this
-               * prefix too.  The key is the peer's IP or swpX, the value is the
-               * hostname if we know it and "" if not.
-               */
-              json_peer = json_object_new_object();
-
-              if (peer->hostname)
-                json_object_string_add(json_peer, "hostname", peer->hostname);
-
-              if (!json_adv_to)
+              if (json && !json_adv_to)
                 json_adv_to = json_object_new_object();
 
-              if (peer->conf_if)
-                json_object_object_add(json_adv_to, peer->conf_if, json_peer);
-              else
-                json_object_object_add(json_adv_to,
-                                       sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN),
-                                       json_peer);
+              route_vty_out_advertised_to(vty, peer, &first,
+                                          "  Advertised to non peer-group peers:\n ",
+                                          json_adv_to);
             }
-          else
-            {
-             if (! first)
-               vty_out (vty, "  Advertised to non peer-group peers:%s ", VTY_NEWLINE);
+        }
 
-             if (peer->hostname && bgp_flag_check(peer->bgp, BGP_FLAG_SHOW_HOSTNAME))
-               {
-                 if (peer->conf_if)
-                   vty_out (vty, " %s(%s)", peer->hostname, peer->conf_if);
-                 else
-                   vty_out (vty, " %s(%s)", peer->hostname,
-                            sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
-               }
-             else
-               {
-                 if (peer->conf_if)
-                   vty_out (vty, " %s", peer->conf_if);
-                 else
-                   vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN));
-               }
+      if (json)
+        {
+          if (json_adv_to)
+            {
+              json_object_object_add(json, "advertisedTo", json_adv_to);
             }
-           first = 1;
-       }
-    }
-
-  if (json)
-    {
-      if (first)
+        }
+      else
         {
-          json_object_object_add(json, "advertisedTo", json_adv_to);
+          if (first)
+            vty_out (vty, "  Not advertised to any peer");
+          vty_out (vty, "%s", VTY_NEWLINE);
         }
     }
-  else
-    {
-      if (!first)
-        vty_out (vty, "  Not advertised to any peer");
-      vty_out (vty, "%s", VTY_NEWLINE);
-    }
 }
 
 /* Display specified route of BGP table. */
@@ -12093,6 +12175,7 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
   json_object *json_scode = NULL;
   json_object *json_ocode = NULL;
   json_object *json_ar = NULL;
+  struct peer_af *paf;
 
   if (use_json)
     {
@@ -12206,46 +12289,49 @@ show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
         }
       else
         {
-          adj = bgp_adj_peer_lookup(peer, rn);
-          if (adj)
-            {
-              if (header1)
+          for (adj = rn->adj_out; adj; adj = adj->next)
+            SUBGRP_FOREACH_PEER(adj->subgroup, paf)
+              if (paf->peer == peer)
                 {
-                  if (use_json)
+                  if (header1)
                     {
-                      json_object_int_add(json, "bgpTableVersion", table->version);
-                      json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
-                      json_object_object_add(json, "bgpStatusCodes", json_scode);
-                      json_object_object_add(json, "bgpOriginCodes", json_ocode);
+                      if (use_json)
+                        {
+                          json_object_int_add(json, "bgpTableVersion", table->version);
+                          json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
+                          json_object_object_add(json, "bgpStatusCodes", json_scode);
+                          json_object_object_add(json, "bgpOriginCodes", json_ocode);
+                        }
+                      else
+                        {
+                          vty_out (vty, "BGP table version is %" PRIu64 ", local router ID is %s%s", table->version,
+                                   inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                          vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+                          vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+                        }
+                      header1 = 0;
                     }
-                  else
+
+                  if (header2)
                     {
-                      vty_out (vty, "BGP table version is %" PRIu64 ", local router ID is %s%s", table->version,
-                               inet_ntoa (bgp->router_id), VTY_NEWLINE);
-                      vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
-                      vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
+                      if (!use_json)
+                        vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
+                      header2 = 0;
                     }
-                  header1 = 0;
-                }
-              if (header2)
-                {
-                  if (!use_json)
-                    vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
-                  header2 = 0;
-                }
-              if (adj->attr)
-                {
-                  bgp_attr_dup(&attr, adj->attr);
-                  ret = bgp_output_modifier(peer, &rn->p, &attr, afi, safi, rmap_name);
-                  if (ret != RMAP_DENY)
+
+                  if (adj->attr)
                     {
-                      route_vty_out_tmp (vty, &rn->p, &attr, safi, use_json, json_ar);
-                      output_count++;
+                      bgp_attr_dup(&attr, adj->attr);
+                      ret = bgp_output_modifier(peer, &rn->p, &attr, afi, safi, rmap_name);
+                      if (ret != RMAP_DENY)
+                        {
+                          route_vty_out_tmp (vty, &rn->p, &attr, safi, use_json, json_ar);
+                          output_count++;
+                        }
+                      else
+                        filtered_count++;
                     }
-                  else
-                    filtered_count++;
                 }
-            }
         }
     }
   if (use_json)
index 59003438b0bb1c8dedd444aec2e9535f5180677a..0d2134e99cc62d5ebe217978b4bbeea4488c488c 100644 (file)
@@ -304,7 +304,8 @@ extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, saf
 extern int
 subgroup_process_announce_selected (struct update_subgroup *subgrp,
                                    struct bgp_info *selected,
-                                   struct bgp_node *rn);
+                                    struct bgp_node *rn,
+                                    u_int32_t addpath_tx_id);
 
 extern int subgroup_announce_check(struct bgp_info *ri,
                                   struct update_subgroup *subgrp,
index c39c687823e735635cdc3b7b0bc974f6344887b5..c0f0c20b7c47715fe7783a34a2506a70738c4cab 100644 (file)
@@ -1214,7 +1214,7 @@ update_subgroup_copy_adj_out (struct update_subgroup *source,
     /*
      * Copy the adj out.
      */
-    aout_copy = bgp_adj_out_alloc (dest, aout->rn);
+    aout_copy = bgp_adj_out_alloc (dest, aout->rn, aout->addpath_tx_id);
     aout_copy->attr = aout->attr ? bgp_attr_refcount (aout->attr) : NULL;
   }
 }
@@ -1954,3 +1954,10 @@ update_group_clear_update_dbg (struct update_group *updgrp, void *arg)
   UPDGRP_PEER_DBG_OFF(updgrp);
   return UPDWALK_CONTINUE;
 }
+
+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));
+}
index 542517f62e3d25a6c041620a65742b543157590a..1ca62a0a8399d08357bb0c34af6a2a1c0c39f382 100644 (file)
@@ -49,6 +49,7 @@
                              PEER_FLAG_REMOVE_PRIVATE_AS_ALL | \
                              PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
                              PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | \
+                              PEER_FLAG_ADDPATH_TX_ALL_PATHS | \
                              PEER_FLAG_AS_OVERRIDE)
 
 #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
@@ -454,7 +455,8 @@ extern void update_group_announce (struct bgp *bgp);
 extern void update_group_announce_rrclients (struct bgp *bgp);
 extern void peer_af_announce_route (struct peer_af *paf, int combine);
 extern struct bgp_adj_out *bgp_adj_out_alloc (struct update_subgroup *subgrp,
-                                             struct bgp_node *rn);
+                                              struct bgp_node *rn,
+                                              u_int32_t addpath_tx_id);
 extern void bgp_adj_out_remove_subgroup (struct bgp_node *rn,
                                         struct bgp_adj_out *adj,
                                         struct update_subgroup *subgrp);
@@ -465,7 +467,8 @@ bgp_adj_out_set_subgroup (struct bgp_node *rn,
 extern void
 bgp_adj_out_unset_subgroup (struct bgp_node *rn,
                            struct update_subgroup *subgrp,
-                            char withdraw);
+                            char withdraw,
+                            u_int32_t addpath_tx_id);
 void
 subgroup_announce_table (struct update_subgroup *subgrp,
                         struct bgp_table *table, int rsclient);
@@ -476,6 +479,7 @@ extern int
 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);
 
 /*
  * Inline functions
index 16ec20e24d0317d151104db4012123972da2d233..493948e79ad386be6ab56500ebda4542717cd00e 100644 (file)
  ********************/
 
 static inline struct bgp_adj_out *
-adj_lookup (struct bgp_node *rn, struct update_subgroup *subgrp)
+adj_lookup (struct bgp_node *rn, struct update_subgroup *subgrp,
+            u_int32_t addpath_tx_id)
 {
   struct bgp_adj_out *adj;
+  struct peer *peer;
+  afi_t afi;
+  safi_t safi;
+  int addpath_capable;
 
   if (!rn || !subgrp)
     return NULL;
+
+  peer = SUBGRP_PEER (subgrp);
+  afi = SUBGRP_AFI (subgrp);
+  safi = SUBGRP_SAFI (subgrp);
+  addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
+
+  /* update-groups that do not support addpath will pass 0 for
+   * addpath_tx_id so do not both matching against it */
   for (adj = rn->adj_out; adj; adj = adj->next)
-    if (adj->subgroup == subgrp)
-      break;
+    {
+      if (adj->subgroup == subgrp)
+        {
+          if (addpath_capable)
+            {
+              if (adj->addpath_tx_id == addpath_tx_id)
+                {
+                  break;
+                }
+            }
+          else
+            {
+              break;
+            }
+        }
+    }
+
   return adj;
 }
 
@@ -81,6 +109,17 @@ group_announce_route_walkcb (struct update_group *updgrp, void *arg)
 {
   struct updwalk_context *ctx = arg;
   struct update_subgroup *subgrp;
+  struct bgp_info *ri;
+  afi_t afi;
+  safi_t safi;
+  struct peer *peer;
+  struct bgp_adj_out *adj;
+  int addpath_capable;
+
+  afi = UPDGRP_AFI (updgrp);
+  safi = UPDGRP_SAFI (updgrp);
+  peer = UPDGRP_PEER (updgrp);
+  addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
 
   UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
     {
@@ -91,7 +130,66 @@ group_announce_route_walkcb (struct update_group *updgrp, void *arg)
        * coalesce timer fires.
        */
       if (!subgrp->t_coalesce)
-       subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn);
+        {
+          /* An update-group that uses addpath */
+          if (addpath_capable)
+            {
+              /* Look through all of the paths we have advertised for this rn and
+               * send a withdraw for the ones that are no longer present */
+              for (adj = ctx->rn->adj_out; adj; adj = adj->next)
+                {
+                  if (adj->subgroup == subgrp)
+                    {
+                      for (ri = ctx->rn->info; ri; ri = ri->next)
+                        {
+                          if (ri->addpath_tx_id == adj->addpath_tx_id)
+                            {
+                              break;
+                            }
+                        }
+
+                      if (!ri)
+                        {
+                          subgroup_process_announce_selected (subgrp, NULL, ctx->rn, adj->addpath_tx_id);
+                        }
+                    }
+                }
+
+              if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS))
+                {
+                  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);
+                    }
+                }
+
+              if (ctx->ri)
+                subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn, ctx->ri->addpath_tx_id);
+            }
+
+          /* An update-group that does not use addpath */
+          else
+            {
+              if (ctx->ri)
+                {
+                  subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn, ctx->ri->addpath_tx_id);
+                }
+              else
+                {
+                  /* Find the addpath_tx_id of the path we had advertised and
+                   * send a withdraw */
+                  for (adj = ctx->rn->adj_out; adj; adj = adj->next)
+                    {
+                      if (adj->subgroup == subgrp)
+                        {
+                          subgroup_process_announce_selected (subgrp, NULL, ctx->rn, adj->addpath_tx_id);
+                        }
+                    }
+                }
+            }
+        }
     }
 
   return UPDWALK_CONTINUE;
@@ -265,7 +363,8 @@ update_group_announce_rrc_walkcb (struct update_group *updgrp, void *arg)
  * primarily its association with the subgroup and the prefix.
  */
 struct bgp_adj_out *
-bgp_adj_out_alloc (struct update_subgroup *subgrp, struct bgp_node *rn)
+bgp_adj_out_alloc (struct update_subgroup *subgrp, struct bgp_node *rn,
+                   u_int32_t addpath_tx_id)
 {
   struct bgp_adj_out *adj;
 
@@ -277,6 +376,8 @@ bgp_adj_out_alloc (struct update_subgroup *subgrp, struct bgp_node *rn)
       bgp_lock_node (rn);
       adj->rn = rn;
     }
+
+  adj->addpath_tx_id = addpath_tx_id;
   TAILQ_INSERT_TAIL (&(subgrp->adjq), adj, subgrp_adj_train);
   SUBGRP_INCR_STAT (subgrp, adj_count);
   return adj;
@@ -335,11 +436,11 @@ bgp_adj_out_set_subgroup (struct bgp_node *rn,
     return;
 
   /* Look for adjacency information. */
-  adj = adj_lookup (rn, subgrp);
+  adj = adj_lookup (rn, subgrp, binfo->addpath_tx_id);
 
   if (!adj)
     {
-      adj = bgp_adj_out_alloc (subgrp, rn);
+      adj = bgp_adj_out_alloc (subgrp, rn, binfo->addpath_tx_id);
       if (!adj)
        return;
     }
@@ -388,7 +489,8 @@ bgp_adj_out_set_subgroup (struct bgp_node *rn,
 void
 bgp_adj_out_unset_subgroup (struct bgp_node *rn,
                            struct update_subgroup *subgrp,
-                            char withdraw)
+                            char withdraw,
+                            u_int32_t addpath_tx_id)
 {
   struct bgp_adj_out *adj;
   struct bgp_advertise *adv;
@@ -397,53 +499,46 @@ bgp_adj_out_unset_subgroup (struct bgp_node *rn,
   if (DISABLE_BGP_ANNOUNCE)
     return;
 
-  /* Lookup existing adjacency, if it is not there return immediately.  */
-  adj = adj_lookup (rn, subgrp);
+  /* Lookup existing adjacency */
+  if ((adj = adj_lookup (rn, subgrp, addpath_tx_id)) != NULL)
+    {
+      /* Clean up previous advertisement.  */
+      if (adj->adv)
+        bgp_advertise_clean_subgroup (subgrp, adj);
 
-  if (!adj)
-    goto done;
+      if (adj->attr && withdraw)
+        {
+          /* We need advertisement structure.  */
+          adj->adv = bgp_advertise_new ();
+          adv = adj->adv;
+          adv->rn = rn;
+          adv->adj = adj;
+
+          /* Note if we need to trigger a packet write */
+          if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw))
+            trigger_write = 1;
+          else
+            trigger_write = 0;
 
-  /* Clean up previous advertisement.  */
-  if (adj->adv)
-    bgp_advertise_clean_subgroup (subgrp, adj);
+          /* Add to synchronization entry for withdraw announcement.  */
+          BGP_ADV_FIFO_ADD (&subgrp->sync->withdraw, &adv->fifo);
 
-  if (adj->attr && withdraw)
-    {
-      /* We need advertisement structure.  */
-      adj->adv = bgp_advertise_new ();
-      adv = adj->adv;
-      adv->rn = rn;
-      adv->adj = adj;
-
-      /* Note if we need to trigger a packet write */
-      if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw))
-        trigger_write = 1;
+          /* Schedule packet write, if FIFO is getting its first entry. */
+          if (trigger_write)
+            subgroup_trigger_write(subgrp);
+        }
       else
-        trigger_write = 0;
-
-      /* Add to synchronization entry for withdraw announcement.  */
-      BGP_ADV_FIFO_ADD (&subgrp->sync->withdraw, &adv->fifo);
-
-      /* Schedule packet write, if FIFO is getting its first entry. */
-      if (trigger_write)
-        subgroup_trigger_write(subgrp);
-    }
-  else
-    {
-      /* Remove myself from adjacency. */
-      BGP_ADJ_OUT_DEL (rn, adj);
+        {
+          /* Remove myself from adjacency. */
+          BGP_ADJ_OUT_DEL (rn, adj);
 
-      /* Free allocated information.  */
-      adj_free (adj);
+          /* Free allocated information.  */
+          adj_free (adj);
 
-      bgp_unlock_node (rn);
+          bgp_unlock_node (rn);
+        }
     }
 
-  /*
-   * Fall through.
-   */
-
-done:
   subgrp->version = max (subgrp->version, rn->version);
 }
 
@@ -492,10 +587,12 @@ subgroup_announce_table (struct update_subgroup *subgrp,
   struct peer *onlypeer;
   afi_t afi;
   safi_t safi;
+  int addpath_capable;
 
   peer = SUBGRP_PEER (subgrp);
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
+  addpath_capable = bgp_addpath_encode_tx (peer, afi, safi);
 
   onlypeer = ((SUBGRP_PCOUNT (subgrp) == 1) ?
              (SUBGRP_PFIRST (subgrp))->peer : NULL);
@@ -515,13 +612,15 @@ subgroup_announce_table (struct update_subgroup *subgrp,
   for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
     for (ri = rn->info; ri; ri = ri->next)
 
-      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
+      if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) ||
+          (addpath_capable &&
+           CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS)))
        {
          if (!rsclient
              && subgroup_announce_check (ri, subgrp, &rn->p, &attr))
            bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri);
          else
-           bgp_adj_out_unset_subgroup (rn, subgrp, 1);
+           bgp_adj_out_unset_subgroup (rn, subgrp, 1, ri->addpath_tx_id);
        }
 
   /*
@@ -704,7 +803,7 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
 #endif /* HAVE_IPV6 */
 
           rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, &p, NULL);
-          bgp_adj_out_unset_subgroup (rn, subgrp, 0);
+          bgp_adj_out_unset_subgroup (rn, subgrp, 0, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
        }
     }
 
index 43aea264eb4cbc5900d09212b297557cf7090ef0..320eef21d28c2f6e08d34bfa6e9c2dd6677dc2ae 100644 (file)
@@ -600,6 +600,14 @@ subgroup_packets_to_build (struct update_subgroup *subgrp)
   return 0;
 }
 
+static void
+bgp_info_addpath_tx_str (int addpath_encode, u_int32_t addpath_tx_id,
+                         char *buf)
+{
+  if (addpath_encode)
+    sprintf(buf, " with addpath ID %d", addpath_tx_id);
+}
+
 /* Make BGP update packet.  */
 struct bpacket *
 subgroup_update_packet (struct update_subgroup *subgrp)
@@ -625,7 +633,8 @@ subgroup_update_packet (struct update_subgroup *subgrp)
   char send_attr_str[BUFSIZ];
   int send_attr_printed = 0;
   int num_pfx = 0;
-
+  int addpath_encode = 0;
+  u_int32_t addpath_tx_id = 0;
 
   if (!subgrp)
     return NULL;
@@ -644,14 +653,16 @@ subgroup_update_packet (struct update_subgroup *subgrp)
 
   bpacket_attr_vec_arr_reset (&vecarr);
 
+  addpath_encode = bgp_addpath_encode_tx (peer, afi, safi);
+
   adv = BGP_ADV_FIFO_HEAD (&subgrp->sync->update);
   while (adv)
     {
       assert (adv->rn);
       rn = adv->rn;
       adj = adv->adj;
-      if (adv->binfo)
-       binfo = adv->binfo;
+      addpath_tx_id = adj->addpath_tx_id;
+      binfo = adv->binfo;
 
       space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
                         BGP_MAX_PACKET_SIZE_OVERFLOW;
@@ -691,7 +702,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
          total_attr_len = bgp_packet_attribute (NULL, peer, s,
                                                 adv->baa->attr, &vecarr,
                                                 NULL, afi, safi,
-                                                from, NULL, NULL);
+                                                from, NULL, NULL, 0, 0);
 
           space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
                             BGP_MAX_PACKET_SIZE_OVERFLOW;
@@ -721,7 +732,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
 
       if ((afi == AFI_IP && safi == SAFI_UNICAST) &&
           !peer_cap_enhe(peer))
-       stream_put_prefix (s, &rn->p);
+       stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
       else
        {
          /* Encode the prefix in MP_REACH_NLRI attribute */
@@ -737,14 +748,16 @@ subgroup_update_packet (struct update_subgroup *subgrp)
            mpattrlen_pos = bgp_packet_mpattr_start (snlri, afi, safi,
                                          (peer_cap_enhe(peer) ? AFI_IP6 : afi),
                                          &vecarr, adv->baa->attr);
-         bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag);
+          bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag,
+                                    addpath_encode, addpath_tx_id);
        }
 
       num_pfx++;
 
       if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
        {
-         char buf[INET6_BUFSIZ];
+          char buf[INET6_BUFSIZ];
+          char tx_id_buf[30];
 
           if (!send_attr_printed)
             {
@@ -753,10 +766,11 @@ subgroup_update_packet (struct update_subgroup *subgrp)
               send_attr_printed = 1;
             }
 
-         zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d",
-               subgrp->update_group->id, subgrp->id,
-               inet_ntop (rn->p.family, &(rn->p.u.prefix), buf,
-                          INET6_BUFSIZ), rn->p.prefixlen);
+          bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
+          zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s",
+                      subgrp->update_group->id, subgrp->id,
+                      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
+                      rn->p.prefixlen, tx_id_buf);
        }
 
       /* Synchnorize attribute.  */
@@ -831,6 +845,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
   int space_remaining = 0;
   int space_needed = 0;
   int num_pfx = 0;
+  int addpath_encode = 0;
+  u_int32_t addpath_tx_id = 0;
 
   if (!subgrp)
     return NULL;
@@ -843,12 +859,14 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
   safi = SUBGRP_SAFI (subgrp);
   s = subgrp->work;
   stream_reset (s);
+  addpath_encode = bgp_addpath_encode_tx (peer, afi, safi);
 
   while ((adv = BGP_ADV_FIFO_HEAD (&subgrp->sync->withdraw)) != NULL)
     {
       assert (adv->rn);
       adj = adv->adj;
       rn = adv->rn;
+      addpath_tx_id = adj->addpath_tx_id;
 
       space_remaining = STREAM_REMAIN (s) -
                         BGP_MAX_PACKET_SIZE_OVERFLOW;
@@ -868,7 +886,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
 
       if (afi == AFI_IP && safi == SAFI_UNICAST &&
           !peer_cap_enhe(peer))
-       stream_put_prefix (s, &rn->p);
+       stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
       else
        {
          struct prefix_rd *prd = NULL;
@@ -886,19 +904,21 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
              mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
            }
 
-         bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL);
+         bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
+                                       addpath_encode, addpath_tx_id);
        }
 
       num_pfx++;
 
       if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
        {
-         char buf[INET6_BUFSIZ];
-
-         zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d -- unreachable",
-               subgrp->update_group->id, subgrp->id,
-               inet_ntop (rn->p.family, &(rn->p.u.prefix), buf,
-                          INET6_BUFSIZ), rn->p.prefixlen);
+          char buf[INET6_BUFSIZ];
+          char tx_id_buf[30];
+          bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
+         zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+                      subgrp->update_group->id, subgrp->id,
+                      inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
+                      rn->p.prefixlen, tx_id_buf);
        }
 
       subgrp->scount--;
@@ -951,6 +971,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   afi_t afi;
   safi_t safi;
   struct bpacket_attr_vec_arr vecarr;
+  int addpath_encode = 0;
 
   if (DISABLE_BGP_ANNOUNCE)
     return;
@@ -962,6 +983,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
   bpacket_attr_vec_arr_reset (&vecarr);
+  addpath_encode = bgp_addpath_encode_tx (peer, afi, safi);
 
   if (afi == AFI_IP)
     str2prefix ("0.0.0.0/0", &p);
@@ -975,13 +997,15 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
     {
       char attrstr[BUFSIZ];
       char buf[INET6_BUFSIZ];
+      char tx_id_buf[30];
       attrstr[0] = '\0';
 
       bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
-      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d %s",
-           (SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
-           inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
-           p.prefixlen, attrstr);
+      bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
+      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s %s",
+                  (SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
+                  inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
+                  p.prefixlen, tx_id_buf, attrstr);
     }
 
   s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -996,7 +1020,9 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   pos = stream_get_endp (s);
   stream_putw (s, 0);
   total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &vecarr, &p,
-                                        afi, safi, from, NULL, NULL);
+                                        afi, safi, from, NULL, NULL,
+                                         addpath_encode,
+                                         BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
 
   /* Set Total Path Attribute Length. */
   stream_putw_at (s, pos, total_attr_len);
@@ -1004,7 +1030,7 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
   /* NLRI set. */
   if (p.family == AF_INET && safi == SAFI_UNICAST &&
       !peer_cap_enhe(peer))
-    stream_put_prefix (s, &p);
+    stream_put_prefix_addpath (s, &p, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
 
   /* Set size. */
   bgp_packet_set_size (s);
@@ -1027,6 +1053,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   size_t mplen_pos = 0;
   afi_t afi;
   safi_t safi;
+  int addpath_encode = 0;
 
   if (DISABLE_BGP_ANNOUNCE)
     return;
@@ -1034,6 +1061,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   peer = SUBGRP_PEER (subgrp);
   afi = SUBGRP_AFI (subgrp);
   safi = SUBGRP_SAFI (subgrp);
+  addpath_encode = bgp_addpath_encode_tx (peer, afi, safi);
 
   if (afi == AFI_IP)
     str2prefix ("0.0.0.0/0", &p);
@@ -1047,14 +1075,13 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   if (bgp_debug_update(NULL, &p, subgrp->update_group, 0))
     {
       char buf[INET6_BUFSIZ];
+      char tx_id_buf[INET6_BUFSIZ];
 
-      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d -- unreachable",
-           (SUBGRP_UPDGRP (subgrp))->id, subgrp->id, inet_ntop (p.family,
-                                                                &(p.u.
-                                                                  prefix),
-                                                                buf,
-                                                                INET6_BUFSIZ),
-           p.prefixlen);
+      bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
+      zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+                  (SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
+                  inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
+                  p.prefixlen, tx_id_buf);
     }
 
   s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1070,7 +1097,8 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
   if (p.family == AF_INET && safi == SAFI_UNICAST &&
       !peer_cap_enhe(peer))
     {
-      stream_put_prefix (s, &p);
+      stream_put_prefix_addpath (s, &p, addpath_encode,
+                                 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
 
       unfeasible_len = stream_get_endp (s) - cp - 2;
 
@@ -1086,7 +1114,9 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
       stream_putw (s, 0);
       mp_start = stream_get_endp (s);
       mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
-      bgp_packet_mpunreach_prefix (s, &p, afi, safi, NULL, NULL);
+      bgp_packet_mpunreach_prefix (s, &p, afi, safi, NULL, NULL,
+                                   addpath_encode,
+                                   BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
 
       /* Set the mp_unreach attr's length */
       bgp_packet_mpunreach_end (s, mplen_pos);
index f7d5af11267b3623d57b353aaa9dbc6410cd1dfc..c021e8297565663a661d28422c20c2f674607660 100644 (file)
@@ -5771,6 +5771,38 @@ DEFUN (no_neighbor_ttl_security,
   return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer));
 }
 
+DEFUN (neighbor_addpath_tx_all_paths,
+       neighbor_addpath_tx_all_paths_cmd,
+       NEIGHBOR_CMD2 "addpath-tx-all-paths",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Use addpath to advertise all paths to a neighbor\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_ALL_PATHS);
+}
+
+DEFUN (no_neighbor_addpath_tx_all_paths,
+       no_neighbor_addpath_tx_all_paths_cmd,
+       NO_NEIGHBOR_CMD2 "addpath-tx-all-paths",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Use addpath to advertise all paths to a neighbor\n")
+{
+  return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+                                bgp_node_safi (vty),
+                                PEER_FLAG_ADDPATH_TX_ALL_PATHS);
+}
+
 /* Address family configuration.  */
 DEFUN (address_family_ipv4,
        address_family_ipv4_cmd,
@@ -8472,7 +8504,7 @@ bgp_adj_out_count (struct peer *peer, int afi, int safi)
   table = peer->bgp->rib[afi][safi];
   if (!table) return(0);
   for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-    if (bgp_adj_out_lookup(peer, NULL, afi, safi, rn))
+    if (bgp_adj_out_lookup(peer, rn, 0))
        count++;
   return (count);
 }
@@ -9247,6 +9279,9 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
       else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
         json_object_boolean_true_add(json_addr, "privateAsNumsRemovedInUpdatesToNbr");
 
+      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_AS_OVERRIDE))
         json_object_string_add(json_addr, "overrideASNsInOutboundUpdates", "ifAspathEqualRemoteAs");
 
@@ -9434,6 +9469,9 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
       else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS))
         vty_out (vty, "  Private AS numbers removed in updates to this neighbor%s", VTY_NEWLINE);
 
+      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_AS_OVERRIDE))
         vty_out (vty, "  Override ASNs in outbound updates if aspath equals remote-as%s", VTY_NEWLINE);
 
@@ -13171,6 +13209,20 @@ bgp_vty_init (void)
   install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd);
   install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd);
 
+  /* "neighbor addpath-tx-all-paths" commands.*/
+  install_element (BGP_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4M_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV4M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6M_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_IPV6M_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_VPNV4_NODE, &neighbor_addpath_tx_all_paths_cmd);
+  install_element (BGP_VPNV4_NODE, &no_neighbor_addpath_tx_all_paths_cmd);
+
   /* "neighbor passive" commands. */
   install_element (BGP_NODE, &neighbor_passive_cmd);
   install_element (BGP_NODE, &no_neighbor_passive_cmd);
index ec5ce9bb9934f5c5f758ef3192855cc76d9fa233..1edb9229d27fdd543e0b336c2ca0e2e8de39cb94 100644 (file)
@@ -2817,6 +2817,7 @@ bgp_create (as_t *as, const char *name)
   bgp_flag_set (bgp, BGP_FLAG_SHOW_HOSTNAME);
   bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
   bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
+  bgp->addpath_tx_id = BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE;
 
   bgp->as = *as;
 
@@ -3460,25 +3461,29 @@ static const struct peer_flag_action peer_flag_action_list[] =
 
 static const struct peer_flag_action peer_af_flag_action_list[] =
   {
-    { PEER_FLAG_NEXTHOP_SELF,             1, peer_change_reset_out },
     { PEER_FLAG_SEND_COMMUNITY,           1, peer_change_reset_out },
     { PEER_FLAG_SEND_EXT_COMMUNITY,       1, peer_change_reset_out },
-    { PEER_FLAG_SOFT_RECONFIG,            0, peer_change_reset_in },
+    { PEER_FLAG_NEXTHOP_SELF,             1, peer_change_reset_out },
     { PEER_FLAG_REFLECTOR_CLIENT,         1, peer_change_reset },
     { PEER_FLAG_RSERVER_CLIENT,           1, peer_change_reset },
+    { PEER_FLAG_SOFT_RECONFIG,            0, peer_change_reset_in },
     { PEER_FLAG_AS_PATH_UNCHANGED,        1, peer_change_reset_out },
     { PEER_FLAG_NEXTHOP_UNCHANGED,        1, peer_change_reset_out },
     { PEER_FLAG_MED_UNCHANGED,            1, peer_change_reset_out },
+    // PEER_FLAG_DEFAULT_ORIGINATE
     { PEER_FLAG_REMOVE_PRIVATE_AS,        1, peer_change_reset_out },
-    { PEER_FLAG_REMOVE_PRIVATE_AS_ALL,    1, peer_change_reset_out },
-    { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,1, peer_change_reset_out },
     { PEER_FLAG_ALLOWAS_IN,               0, peer_change_reset_in },
     { PEER_FLAG_ORF_PREFIX_SM,            1, peer_change_reset },
     { PEER_FLAG_ORF_PREFIX_RM,            1, peer_change_reset },
+    // PEER_FLAG_MAX_PREFIX
+    // PEER_FLAG_MAX_PREFIX_WARNING
     { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED,  0, peer_change_reset_out },
     { PEER_FLAG_FORCE_NEXTHOP_SELF,       1, peer_change_reset_out },
+    { PEER_FLAG_REMOVE_PRIVATE_AS_ALL,    1, peer_change_reset_out },
+    { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,1, peer_change_reset_out },
     { 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 },
     { 0, 0, 0 }
   };
 
@@ -3680,6 +3685,9 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
   struct listnode *node, *nnode;
   struct peer_group *group;
   struct peer_flag_action action;
+  struct peer *tmp_peer;
+  struct bgp *bgp;
+  int addpath_tx_used;
 
   memset (&action, 0, sizeof (struct peer_flag_action));
   size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
@@ -3746,42 +3754,68 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
     {
       group = peer->group;
       
-      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
        {
-         if (! peer->af_group[afi][safi])
+         if (! tmp_peer->af_group[afi][safi])
            continue;
 
-         if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
+         if (set && CHECK_FLAG (tmp_peer->af_flags[afi][safi], flag) == flag)
            continue;
 
-         if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
+         if (! set && ! CHECK_FLAG (tmp_peer->af_flags[afi][safi], flag))
            continue;
 
          if (set)
-           SET_FLAG (peer->af_flags[afi][safi], flag);
+           SET_FLAG (tmp_peer->af_flags[afi][safi], flag);
          else
-           UNSET_FLAG (peer->af_flags[afi][safi], flag);
+           UNSET_FLAG (tmp_peer->af_flags[afi][safi], flag);
 
-         if (peer->status == Established)
+         if (tmp_peer->status == Established)
            {
              if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
-               bgp_clear_adj_in (peer, afi, safi);
+               bgp_clear_adj_in (tmp_peer, afi, safi);
              else
                {
                  if (flag == PEER_FLAG_REFLECTOR_CLIENT)
-                   peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
+                   tmp_peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
                  else if (flag == PEER_FLAG_RSERVER_CLIENT)
-                   peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
+                   tmp_peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
                  else if (flag == PEER_FLAG_ORF_PREFIX_SM)
-                   peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+                   tmp_peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
                  else if (flag == PEER_FLAG_ORF_PREFIX_RM)
-                   peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+                   tmp_peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
 
-                 peer_change_action (peer, afi, safi, action.type);
+                 peer_change_action (tmp_peer, afi, safi, action.type);
                }
            }
        }
     }
+
+  /* Track if addpath TX is in use */
+  if (flag & PEER_FLAG_ADDPATH_TX_ALL_PATHS)
+    {
+      bgp = peer->bgp;
+      addpath_tx_used = 0;
+
+      if (set)
+        {
+          addpath_tx_used = 1;
+        }
+      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))
+                {
+                  addpath_tx_used = 1;
+                  break;
+                }
+            }
+        }
+
+      bgp->addpath_tx_used[afi][safi] = addpath_tx_used;
+    }
+
   return 0;
 }
 
@@ -6510,6 +6544,11 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
                             addr, VTY_NEWLINE);
       }
 
+  /* 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);
+
   /* ORF capability.  */
   if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) ||
       peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_RM))
index 41bc5ea81c4dea9aadc7324f1b1c5b0a88e2f260..7ed8176b1c952622d2d6a9e33044e95f45b01650 100644 (file)
@@ -315,6 +315,9 @@ struct bgp
 
   u_int32_t wpkt_quanta;  /* per peer packet quanta to write */
   u_int32_t coalesce_time;
+
+  u_int32_t addpath_tx_id;
+  int addpath_tx_used[AFI_MAX][SAFI_MAX];
 };
 
 #define BGP_ROUTE_ADV_HOLD(bgp) \
@@ -364,6 +367,8 @@ struct bgp_nexthop
 #define BGP_ADDPATH_TX     2
 #define BGP_ADDPATH_ID_LEN 4
 
+#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
+
 /* BGP router distinguisher value.  */
 #define BGP_RD_SIZE                8
 
@@ -648,6 +653,7 @@ struct peer
 #define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as replace-as */
 #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 */
 
   /* MD5 password */
   char *password;
index fcdf56f64f6651384e8bc2fb369e7bf158e10833..11f35d884ef0228a65d0b1465cd6292ec2195930 100644 (file)
@@ -752,20 +752,35 @@ stream_put_in6_addr_at (struct stream *s, size_t putp, struct in6_addr *addr)
 
 /* Put prefix by nlri type format. */
 int
-stream_put_prefix (struct stream *s, struct prefix *p)
+stream_put_prefix_addpath (struct stream *s, struct prefix *p,
+                           int addpath_encode, u_int32_t addpath_tx_id)
 {
   size_t psize;
+  size_t psize_with_addpath;
   
   STREAM_VERIFY_SANE(s);
   
   psize = PSIZE (p->prefixlen);
+
+  if (addpath_encode)
+    psize_with_addpath = psize + 4;
+  else
+    psize_with_addpath = psize;
   
-  if (STREAM_WRITEABLE (s) < (psize + sizeof (u_char)))
+  if (STREAM_WRITEABLE (s) < (psize_with_addpath + sizeof (u_char)))
     {
       STREAM_BOUND_WARN (s, "put");
       return 0;
     }
   
+  if (addpath_encode)
+    {
+        s->data[s->endp++] = (u_char)(addpath_tx_id >> 24);
+        s->data[s->endp++] = (u_char)(addpath_tx_id >> 16);
+        s->data[s->endp++] = (u_char)(addpath_tx_id >>  8);
+        s->data[s->endp++] = (u_char)addpath_tx_id;
+    }
+
   s->data[s->endp++] = p->prefixlen;
   memcpy (s->data + s->endp, &p->u.prefix, psize);
   s->endp += psize;
@@ -773,6 +788,13 @@ stream_put_prefix (struct stream *s, struct prefix *p)
   return psize;
 }
 
+int
+stream_put_prefix (struct stream *s, struct prefix *p)
+{
+  return stream_put_prefix_addpath (s, p, 0, 0);
+}
+
+
 /* Read size from fd. */
 int
 stream_read (struct stream *s, int fd, size_t size)
index 3efabe358d67796969db0f11ed9b475c00987ac4..32d2668310c9349d61e93840558d32046621f068 100644 (file)
@@ -175,6 +175,9 @@ extern int stream_put_ipv4 (struct stream *, u_int32_t);
 extern int stream_put_in_addr (struct stream *, struct in_addr *);
 extern int stream_put_in_addr_at (struct stream *, size_t, struct in_addr *);
 extern int stream_put_in6_addr_at (struct stream *, size_t, struct in6_addr *);
+extern int stream_put_prefix_addpath (struct stream *, struct prefix *,
+                                      int addpath_encode,
+                                      u_int32_t addpath_tx_id);
 extern int stream_put_prefix (struct stream *, struct prefix *);
 
 extern void stream_get (void *, struct stream *, size_t);