forked from Mirror/frr
BGP: support for addpath TX
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#
This commit is contained in:
parent
3490002086
commit
adbac85e10
|
@ -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));
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
352
bgpd/bgp_route.c
352
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 (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_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 (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,69 +8340,37 @@ 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));
|
||||
}
|
||||
}
|
||||
first = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (json)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
json_object_object_add(json, "advertisedTo", json_adv_to);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!first)
|
||||
vty_out (vty, " Not advertised to any peer");
|
||||
vty_out (vty, "%s", VTY_NEWLINE);
|
||||
|
||||
if (json)
|
||||
{
|
||||
if (json_adv_to)
|
||||
{
|
||||
json_object_object_add(json, "advertisedTo", json_adv_to);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first)
|
||||
vty_out (vty, " Not advertised to any peer");
|
||||
vty_out (vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
if (!adj)
|
||||
goto done;
|
||||
|
||||
/* Clean up previous advertisement. */
|
||||
if (adj->adv)
|
||||
bgp_advertise_clean_subgroup (subgrp, adj);
|
||||
|
||||
if (adj->attr && withdraw)
|
||||
/* Lookup existing adjacency */
|
||||
if ((adj = adj_lookup (rn, subgrp, addpath_tx_id)) != NULL)
|
||||
{
|
||||
/* We need advertisement structure. */
|
||||
adj->adv = bgp_advertise_new ();
|
||||
adv = adj->adv;
|
||||
adv->rn = rn;
|
||||
adv->adj = adj;
|
||||
/* Clean up previous advertisement. */
|
||||
if (adj->adv)
|
||||
bgp_advertise_clean_subgroup (subgrp, adj);
|
||||
|
||||
/* Note if we need to trigger a packet write */
|
||||
if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw))
|
||||
trigger_write = 1;
|
||||
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;
|
||||
|
||||
/* 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
|
||||
trigger_write = 0;
|
||||
{
|
||||
/* Remove myself from adjacency. */
|
||||
BGP_ADJ_OUT_DEL (rn, adj);
|
||||
|
||||
/* Add to synchronization entry for withdraw announcement. */
|
||||
BGP_ADV_FIFO_ADD (&subgrp->sync->withdraw, &adv->fifo);
|
||||
/* Free allocated information. */
|
||||
adj_free (adj);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
73
bgpd/bgpd.c
73
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))
|
||||
|
|
|
@ -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;
|
||||
|
|
26
lib/stream.c
26
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue