diff options
author | Daniel Walton <dwalton@cumulusnetworks.com> | 2015-11-05 18:29:43 +0100 |
---|---|---|
committer | Daniel Walton <dwalton@cumulusnetworks.com> | 2015-11-05 18:29:43 +0100 |
commit | adbac85e10692e76c01e831d658958c9f269f18f (patch) | |
tree | 84eb4707a775d00bae3761e363a27e5455bdf69f | |
parent | debian: Modify Quagga cumulus version in debian packaging (diff) | |
download | frr-adbac85e10692e76c01e831d658958c9f269f18f.tar.xz frr-adbac85e10692e76c01e831d658958c9f269f18f.zip |
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#
-rw-r--r-- | bgpd/bgp_advertise.c | 29 | ||||
-rw-r--r-- | bgpd/bgp_advertise.h | 8 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 31 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 9 | ||||
-rw-r--r-- | bgpd/bgp_mplsvpn.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_open.c | 29 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 348 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_updgrp.c | 9 | ||||
-rw-r--r-- | bgpd/bgp_updgrp.h | 8 | ||||
-rw-r--r-- | bgpd/bgp_updgrp_adv.c | 199 | ||||
-rw-r--r-- | bgpd/bgp_updgrp_packet.c | 98 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 54 | ||||
-rw-r--r-- | bgpd/bgpd.c | 73 | ||||
-rw-r--r-- | bgpd/bgpd.h | 6 | ||||
-rw-r--r-- | lib/stream.c | 26 | ||||
-rw-r--r-- | lib/stream.h | 3 |
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); |