summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_advertise.c29
-rw-r--r--bgpd/bgp_advertise.h8
-rw-r--r--bgpd/bgp_attr.c31
-rw-r--r--bgpd/bgp_attr.h9
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_open.c29
-rw-r--r--bgpd/bgp_packet.c2
-rw-r--r--bgpd/bgp_route.c348
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_updgrp.c9
-rw-r--r--bgpd/bgp_updgrp.h8
-rw-r--r--bgpd/bgp_updgrp_adv.c199
-rw-r--r--bgpd/bgp_updgrp_packet.c98
-rw-r--r--bgpd/bgp_vty.c54
-rw-r--r--bgpd/bgpd.c73
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--lib/stream.c26
-rw-r--r--lib/stream.h3
18 files changed, 656 insertions, 281 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 70d878739..73b2619c2 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -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));
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index d5b737b9e..ae6e6bd14 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -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 */
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 3a031e0db..d37fa1e79 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -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);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index a846faf67..789422f64 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -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
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index b667c4a2c..d3081887c 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -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. */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index e346d7896..2a168899f 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -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. */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f7336ea2f..4a99ad4c6 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -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)
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 820c3cfd9..6c7a24239 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -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,
@@ -7213,6 +7232,57 @@ flap_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo,
}
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,
json_object *json_paths)
@@ -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)
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 59003438b..0d2134e99 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -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,
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index c39c68782..c0f0c20b7 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -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));
+}
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index 542517f62..1ca62a0a8 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -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
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 16ec20e24..493948e79 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -56,15 +56,43 @@
********************/
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);
}
}
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 43aea264e..320eef21d 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -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);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index f7d5af112..c021e8297 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index ec5ce9bb9..1edb9229d 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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))
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 41bc5ea81..7ed8176b1 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -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;
diff --git a/lib/stream.c b/lib/stream.c
index fcdf56f64..11f35d884 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -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)
diff --git a/lib/stream.h b/lib/stream.h
index 3efabe358..32d266831 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -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);