summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_updgrp_adv.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_updgrp_adv.c')
-rw-r--r--bgpd/bgp_updgrp_adv.c199
1 files changed, 149 insertions, 50 deletions
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);
}
}