summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c38
-rw-r--r--proto/bgp/bgp.c21
-rw-r--r--proto/bgp/bgp.h7
-rw-r--r--proto/bgp/packets.c5
4 files changed, 49 insertions, 22 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 2ff3f3f3..a1f5791a 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1651,8 +1651,9 @@ bgp_init_prefix_table(struct bgp_channel *bc)
}
static struct bgp_prefix *
-bgp_get_prefix(struct bgp_pending_tx *c, const net_addr *net, u32 path_id, int add_path_tx)
+bgp_get_prefix(struct bgp_pending_tx *c, const net_addr *net, struct rte_src *src, int add_path_tx)
{
+ u32 path_id = src->global_id;
u32 path_id_hash = add_path_tx ? path_id : 0;
/* We must use a different hash function than the rtable */
u32 hash = u32_hash(net_hash(net) ^ u32_hash(path_id_hash));
@@ -1670,6 +1671,7 @@ bgp_get_prefix(struct bgp_pending_tx *c, const net_addr *net, u32 path_id, int a
px->hash = hash;
px->path_id = path_id;
net_copy(px->net, net);
+ rt_lock_source(src);
HASH_INSERT2(c->prefix_hash, PXH, c->pool, px);
@@ -1737,6 +1739,8 @@ bgp_free_prefix(struct bgp_pending_tx *c, struct bgp_prefix *px)
{
HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
+ rt_unlock_source(rt_find_source_global(px->path_id));
+
if (c->prefix_slab)
sl_free(px);
else
@@ -1777,9 +1781,11 @@ bgp_done_prefix(struct bgp_channel *c, struct bgp_prefix *px, struct bgp_bucket
static void
bgp_pending_tx_rfree(resource *r)
{
- UNUSED struct bgp_pending_tx *ptx = SKIP_BACK(struct bgp_pending_tx, r, r);
+ struct bgp_pending_tx *ptx = SKIP_BACK(struct bgp_pending_tx, r, r);
- /* Do nothing for now. */
+ HASH_WALK(ptx->prefix_hash, next, n)
+ rt_unlock_source(rt_find_source_global(n->path_id));
+ HASH_WALK_END;
}
static void bgp_pending_tx_dump(resource *r UNUSED) { debug("\n"); }
@@ -1953,9 +1959,8 @@ bgp_setup_out_table(struct bgp_channel *c)
int
bgp_preexport(struct channel *C, rte *e)
{
- struct proto *SRC = e->src->proto;
struct bgp_proto *p = (struct bgp_proto *) C->proto;
- struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
+ struct bgp_proto *src = bgp_rte_proto(e);
/* Reject our routes */
if (src == p)
@@ -2024,8 +2029,7 @@ bgp_preexport(struct channel *C, rte *e)
static ea_list *
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
{
- struct proto *SRC = e->src->proto;
- struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
+ struct bgp_proto *src = bgp_rte_proto(e);
struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
ea_list *attrs = attrs0;
eattr *a;
@@ -2143,7 +2147,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, c
struct bgp_proto *p = (void *) P;
struct bgp_channel *c = (void *) C;
struct bgp_bucket *buck;
- u32 path;
+ struct rte_src *path;
if (new)
{
@@ -2155,12 +2159,12 @@ bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, c
/* If attributes are invalid, we fail back to withdraw */
buck = attrs ? bgp_get_bucket(c->ptx, attrs) : bgp_get_withdraw_bucket(c->ptx);
- path = new->src->global_id;
+ path = new->src;
}
else
{
buck = bgp_get_withdraw_bucket(c->ptx);
- path = old->src->global_id;
+ path = old->src;
}
if (bgp_update_prefix(c, bgp_get_prefix(c->ptx, n, path, c->add_path_tx), buck))
@@ -2178,7 +2182,7 @@ bgp_get_neighbor(rte *r)
return as;
/* If AS_PATH is not defined, we treat rte as locally originated */
- struct bgp_proto *p = (void *) r->src->proto;
+ struct bgp_proto *p = bgp_rte_proto(r);
return p->cf->confederation ?: p->local_as;
}
@@ -2208,8 +2212,8 @@ rte_stale(rte *r)
int
bgp_rte_better(rte *new, rte *old)
{
- struct bgp_proto *new_bgp = (struct bgp_proto *) new->src->proto;
- struct bgp_proto *old_bgp = (struct bgp_proto *) old->src->proto;
+ struct bgp_proto *new_bgp = bgp_rte_proto(new);
+ struct bgp_proto *old_bgp = bgp_rte_proto(old);
eattr *x, *y;
u32 n, o;
@@ -2353,8 +2357,8 @@ bgp_rte_better(rte *new, rte *old)
int
bgp_rte_mergable(rte *pri, rte *sec)
{
- struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->src->proto;
- struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->src->proto;
+ struct bgp_proto *pri_bgp = bgp_rte_proto(pri);
+ struct bgp_proto *sec_bgp = bgp_rte_proto(sec);
eattr *x, *y;
u32 p, s;
@@ -2438,8 +2442,8 @@ same_group(rte *r, u32 lpref, u32 lasn)
static inline int
use_deterministic_med(struct rte_storage *r)
{
- struct proto *P = r->rte.src->proto;
- return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
+ struct bgp_proto *p = bgp_rte_proto(&r->rte);
+ return p && p->cf->deterministic_med;
}
int
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index e6d3f125..65673e37 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -518,6 +518,12 @@ bgp_stop(struct bgp_proto *p, int subcode, byte *data, uint len)
p->uncork_ev->data = NULL;
bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
+
+ struct bgp_channel *c;
+ WALK_LIST(c, p->p.channels)
+ if (c->ptx)
+ bgp_free_pending_tx(c);
+
ev_schedule(p->event);
}
@@ -1708,6 +1714,13 @@ done:
return p->p.proto_state;
}
+struct rte_owner_class bgp_rte_owner_class = {
+ .get_route_info = bgp_get_route_info,
+ .rte_better = bgp_rte_better,
+ .rte_mergable = bgp_rte_mergable,
+ .rte_igp_metric = bgp_rte_igp_metric,
+};
+
static struct proto *
bgp_init(struct proto_config *CF)
{
@@ -1721,10 +1734,9 @@ bgp_init(struct proto_config *CF)
P->reload_routes = bgp_reload_routes;
P->feed_begin = bgp_feed_begin;
P->feed_end = bgp_feed_end;
- P->rte_better = bgp_rte_better;
- P->rte_mergable = bgp_rte_mergable;
- P->rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
- P->rte_igp_metric = bgp_rte_igp_metric;
+
+ P->sources.class = &bgp_rte_owner_class;
+ P->sources.rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
p->cf = cf;
p->is_internal = (cf->local_as == cf->remote_as);
@@ -2635,7 +2647,6 @@ struct protocol proto_bgp = {
.reconfigure = bgp_reconfigure,
.copy_config = bgp_copy_config,
.get_status = bgp_get_status,
- .get_route_info = bgp_get_route_info,
.show_proto_info = bgp_show_proto_info
};
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index def7b102..fdd134f4 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -541,6 +541,7 @@ rte_resolvable(const rte *rt)
return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE);
}
+extern struct rte_owner_class bgp_rte_owner_class;
#ifdef LOCAL_DEBUG
#define BGP_FORCE_DEBUG 1
@@ -590,6 +591,12 @@ int bgp_preexport(struct channel *, struct rte *);
void bgp_get_route_info(struct rte *, byte *);
int bgp_total_aigp_metric_(const rte *e, u64 *metric, const struct adata **ad);
+static inline struct bgp_proto *bgp_rte_proto(struct rte *rte)
+{
+ return (rte->src->owner->class == &bgp_rte_owner_class) ?
+ SKIP_BACK(struct bgp_proto, p.sources, rte->src->owner) : NULL;
+}
+
#define BGP_AIGP_METRIC 1
#define BGP_AIGP_MAX U64(0xffffffffffffffff)
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 57c00eb5..1f208432 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1372,6 +1372,8 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, ea_lis
{
if (path_id != s->last_id)
{
+ rt_unlock_source(s->last_src);
+
s->last_src = rt_get_source(&s->proto->p, path_id);
s->last_id = path_id;
@@ -2449,6 +2451,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
s->last_id = 0;
s->last_src = s->proto->p.main_source;
+ rt_lock_source(s->last_src);
/*
* IPv4 BGP and MP-BGP may be used together in one update, therefore we do not
@@ -2475,6 +2478,8 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
rta_free(s->cached_ea);
s->cached_ea = NULL;
+
+ rt_unlock_source(s->last_src);
}
static void