#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_addpath.h"
/********************
* PRIVATE FUNCTIONS
********************/
+static int bgp_adj_out_compare(const struct bgp_adj_out *o1,
+ const struct bgp_adj_out *o2)
+{
+ if (o1->subgroup < o2->subgroup)
+ return -1;
+
+ if (o1->subgroup > o2->subgroup)
+ return 1;
+
+ return 0;
+}
+RB_GENERATE(bgp_adj_out_rb, bgp_adj_out, adj_entry, bgp_adj_out_compare);
static inline struct bgp_adj_out *adj_lookup(struct bgp_node *rn,
struct update_subgroup *subgrp,
uint32_t addpath_tx_id)
{
- struct bgp_adj_out *adj;
+ struct bgp_adj_out *adj, lookup;
struct peer *peer;
afi_t afi;
safi_t 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) {
- if (addpath_capable) {
- if (adj->addpath_tx_id == addpath_tx_id) {
- break;
- }
- } else {
- break;
- }
- }
+ lookup.subgroup = subgrp;
+ adj = RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup);
+ if (adj) {
+ if (addpath_capable) {
+ if (adj->addpath_tx_id == addpath_tx_id)
+ return adj;
+ } else
+ return adj;
}
-
- return adj;
+ return NULL;
}
static void adj_free(struct bgp_adj_out *adj)
XFREE(MTYPE_BGP_ADJ_OUT, adj);
}
+static void subgrp_withdraw_stale_addpath(struct updwalk_context *ctx,
+ struct update_subgroup *subgrp)
+{
+ struct bgp_adj_out *adj, *adj_next;
+ uint32_t id;
+ struct bgp_path_info *pi;
+ afi_t afi = SUBGRP_AFI(subgrp);
+ safi_t safi = SUBGRP_SAFI(subgrp);
+ struct peer *peer = SUBGRP_PEER(subgrp);
+
+ /* Look through all of the paths we have advertised for this rn and send
+ * a withdraw for the ones that are no longer present */
+ RB_FOREACH_SAFE (adj, bgp_adj_out_rb, &ctx->rn->adj_out, adj_next) {
+
+ if (adj->subgroup == subgrp) {
+ for (pi = bgp_node_get_bgp_path_info(ctx->rn);
+ pi; pi = pi->next) {
+ id = bgp_addpath_id_for_peer(peer, afi, safi,
+ &pi->tx_addpath);
+
+ if (id == adj->addpath_tx_id) {
+ break;
+ }
+ }
+
+ if (!pi) {
+ subgroup_process_announce_selected(
+ subgrp, NULL, ctx->rn,
+ adj->addpath_tx_id);
+ }
+ }
+ }
+}
+
static int group_announce_route_walkcb(struct update_group *updgrp, void *arg)
{
struct updwalk_context *ctx = arg;
struct update_subgroup *subgrp;
- struct bgp_info *ri;
+ struct bgp_path_info *pi;
afi_t afi;
safi_t safi;
struct peer *peer;
if (!subgrp->t_coalesce) {
/* 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) {
- adj_next = 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);
- }
- }
- }
+ subgrp_withdraw_stale_addpath(ctx, subgrp);
- for (ri = ctx->rn->info; ri; ri = ri->next) {
+ for (pi = bgp_node_get_bgp_path_info(ctx->rn);
+ pi; pi = pi->next) {
/* Skip the bestpath for now */
- if (ri == ctx->ri)
+ if (pi == ctx->pi)
continue;
subgroup_process_announce_selected(
- subgrp, ri, ctx->rn,
- ri->addpath_tx_id);
+ subgrp, pi, ctx->rn,
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &pi->tx_addpath));
}
/* Process the bestpath last so the "show [ip]
* bgp neighbor x.x.x.x advertised"
* output shows the attributes from the bestpath
*/
- if (ctx->ri)
+ if (ctx->pi)
subgroup_process_announce_selected(
- subgrp, ctx->ri, ctx->rn,
- ctx->ri->addpath_tx_id);
+ subgrp, ctx->pi, ctx->rn,
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &ctx->pi->tx_addpath));
}
/* An update-group that does not use addpath */
else {
- if (ctx->ri) {
+ if (ctx->pi) {
subgroup_process_announce_selected(
- subgrp, ctx->ri, ctx->rn,
- ctx->ri->addpath_tx_id);
+ subgrp, ctx->pi, ctx->rn,
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &ctx->pi->tx_addpath));
} 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) {
- adj_next = adj->next;
-
+ RB_FOREACH_SAFE (adj, bgp_adj_out_rb,
+ &ctx->rn->adj_out,
+ adj_next) {
if (adj->subgroup == subgrp) {
subgroup_process_announce_selected(
subgrp, NULL,
output_count = 0;
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
- for (adj = rn->adj_out; adj; adj = adj->next)
+ RB_FOREACH (adj, bgp_adj_out_rb, &rn->adj_out)
if (adj->subgroup == subgrp) {
if (header1) {
vty_out(vty,
adj = XCALLOC(MTYPE_BGP_ADJ_OUT, sizeof(struct bgp_adj_out));
adj->subgroup = subgrp;
if (rn) {
- BGP_ADJ_OUT_ADD(rn, adj);
+ RB_INSERT(bgp_adj_out_rb, &rn->adj_out, adj);
bgp_lock_node(rn);
adj->rn = rn;
}
void bgp_adj_out_set_subgroup(struct bgp_node *rn,
struct update_subgroup *subgrp, struct attr *attr,
- struct bgp_info *binfo)
+ struct bgp_path_info *path)
{
struct bgp_adj_out *adj = NULL;
struct bgp_advertise *adv;
+ struct peer *peer;
+ afi_t afi;
+ safi_t safi;
+
+ peer = SUBGRP_PEER(subgrp);
+ afi = SUBGRP_AFI(subgrp);
+ safi = SUBGRP_SAFI(subgrp);
if (DISABLE_BGP_ANNOUNCE)
return;
/* Look for adjacency information. */
- adj = adj_lookup(rn, subgrp, binfo->addpath_tx_id);
+ adj = adj_lookup(
+ rn, subgrp,
+ bgp_addpath_id_for_peer(peer, afi, safi, &path->tx_addpath));
if (!adj) {
- adj = bgp_adj_out_alloc(subgrp, rn, binfo->addpath_tx_id);
+ adj = bgp_adj_out_alloc(
+ subgrp, rn,
+ bgp_addpath_id_for_peer(peer, afi, safi,
+ &path->tx_addpath));
if (!adj)
return;
}
adv = adj->adv;
adv->rn = rn;
- assert(adv->binfo == NULL);
- adv->binfo = bgp_info_lock(binfo); /* bgp_info adj_out reference */
+ assert(adv->pathi == NULL);
+ /* bgp_path_info adj_out reference */
+ adv->pathi = bgp_path_info_lock(path);
if (attr)
adv->baa = bgp_advertise_intern(subgrp->hash, attr);
subgroup_trigger_write(subgrp);
} else {
/* Remove myself from adjacency. */
- BGP_ADJ_OUT_DEL(rn, adj);
+ RB_REMOVE(bgp_adj_out_rb, &rn->adj_out, adj);
/* Free allocated information. */
adj_free(adj);
if (adj->adv)
bgp_advertise_clean_subgroup(subgrp, adj);
- BGP_ADJ_OUT_DEL(rn, adj);
+ RB_REMOVE(bgp_adj_out_rb, &rn->adj_out, adj);
adj_free(adj);
}
struct bgp_table *table)
{
struct bgp_node *rn;
- struct bgp_info *ri;
+ struct bgp_path_info *ri;
struct attr attr;
struct peer *peer;
afi_t afi;
subgroup_default_originate(subgrp, 0);
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
- for (ri = rn->info; ri; ri = ri->next)
+ for (ri = bgp_node_get_bgp_path_info(rn); ri; ri = ri->next)
- if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)
+ if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED)
|| (addpath_capable
- && bgp_addpath_tx_path(peer, afi, safi, ri))) {
+ && bgp_addpath_tx_path(
+ peer->addpath_type[afi][safi],
+ ri))) {
if (subgroup_announce_check(rn, ri, subgrp,
&rn->p, &attr))
bgp_adj_out_set_subgroup(rn, subgrp,
else
bgp_adj_out_unset_subgroup(
rn, subgrp, 1,
- ri->addpath_tx_id);
+ bgp_addpath_id_for_peer(
+ peer, afi, safi,
+ &ri->tx_addpath));
}
/*
subgroup_announce_table(subgrp, NULL);
else
for (rn = bgp_table_top(update_subgroup_rib(subgrp)); rn;
- rn = bgp_route_next(rn))
- if ((table = (rn->info)) != NULL)
- subgroup_announce_table(subgrp, table);
+ rn = bgp_route_next(rn)) {
+ table = bgp_node_get_bgp_table_info(rn);
+ if (!table)
+ continue;
+ subgroup_announce_table(subgrp, table);
+ }
}
void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
struct bgp *bgp;
struct attr attr;
struct aspath *aspath;
+ struct bgp_path_info tmp_info;
struct prefix p;
struct peer *from;
struct bgp_node *rn;
- struct bgp_info *ri;
+ struct bgp_path_info *ri;
struct peer *peer;
int ret = RMAP_DENYMATCH;
afi_t afi;
SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
- for (ri = rn->info; ri; ri = ri->next) {
+ for (ri = bgp_node_get_bgp_path_info(rn);
+ ri; ri = ri->next) {
struct attr dummy_attr;
- struct bgp_info info;
/* Provide dummy so the route-map can't modify
* the attributes */
bgp_attr_dup(&dummy_attr, ri->attr);
- info.peer = ri->peer;
- info.attr = &dummy_attr;
+ tmp_info.peer = ri->peer;
+ tmp_info.attr = &dummy_attr;
ret = route_map_apply(
peer->default_rmap[afi][safi].map,
- &rn->p, RMAP_BGP, &info);
+ &rn->p, RMAP_BGP, &tmp_info);
/* The route map might have set attributes. If
* we don't flush them
* input route.
*/
void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi,
- struct bgp_node *rn, struct bgp_info *ri)
+ struct bgp_node *rn, struct bgp_path_info *pi)
{
struct updwalk_context ctx;
- ctx.ri = ri;
+ ctx.pi = pi;
ctx.rn = rn;
update_group_af_walk(bgp, afi, safi, group_announce_route_walkcb, &ctx);
}