summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c50
-rw-r--r--proto/bgp/bgp.c94
-rw-r--r--proto/bgp/bgp.h3
-rw-r--r--proto/bgp/packets.c2
4 files changed, 105 insertions, 44 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 90490b4f..892b26e3 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -2267,30 +2267,44 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
return !old_suppressed;
}
-rte *
-bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
+void
+bgp_rte_modify_stale(struct rt_export_request *req, const net_addr *n, struct rt_pending_export *rpe UNUSED, rte **feed, uint count)
{
- eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
- const struct adata *ad = ea ? ea->u.ptr : NULL;
- uint flags = ea ? ea->flags : BAF_PARTIAL;
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, stale_feed, req);
- if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
- return NULL;
+ do {
+ rte *r = feed[--count];
+ if (r->sender != c->c.in_req.hook)
+ continue;
+
+ /* A new route, do not mark as stale */
+ if (r->stale_cycle == c->c.in_req.hook->stale_set)
+ continue;
+
+ eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
+ const struct adata *ad = ea ? ea->u.ptr : NULL;
+ uint flags = ea ? ea->flags : BAF_PARTIAL;
- if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
- return r;
+ rte e0 = *r;
+ e0.flags |= REF_USE_STALE;
- rta *a = rta_do_cow(r->attrs, pool);
-
- _Thread_local static rte e0;
- e0 = *r;
- e0.attrs = a;
+ if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
+ rte_import(&c->c.in_req, n, NULL, r->src);
- bgp_set_attr_ptr(&(a->eattrs), pool, BA_COMMUNITY, flags,
- int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
- e0.pflags |= BGP_REF_STALE;
+ else if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
+ rte_import(&c->c.in_req, n, &e0, r->src);
- return &e0;
+ else {
+ rta *a = e0.attrs = rta_do_cow(r->attrs, bgp_linpool);
+
+ bgp_set_attr_ptr(&(a->eattrs), bgp_linpool, BA_COMMUNITY, flags,
+ int_set_add(bgp_linpool, ad, BGP_COMM_LLGR_STALE));
+ e0.pflags |= BGP_REF_STALE;
+
+ rte_import(&c->c.in_req, n, &e0, r->src);
+ lp_flush(bgp_linpool);
+ }
+ } while (count);
}
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 78c36bc7..35e9ea59 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -140,6 +140,15 @@ static void bgp_update_bfd(struct bgp_proto *p, const struct bfd_options *bfd);
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
static void bgp_listen_sock_err(sock *sk UNUSED, int err);
+static void bgp_graceful_restart_feed(struct bgp_channel *c);
+static inline void channel_refresh_end_reload(struct channel *c)
+{
+ channel_refresh_end(c);
+
+ if (c->in_table)
+ channel_request_reload(c);
+}
+
/**
* bgp_open - open a BGP instance
* @p: BGP instance
@@ -775,25 +784,25 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
{
case BGP_GRS_NONE:
c->gr_active = BGP_GRS_ACTIVE;
- rt_refresh_begin(c->c.table, &c->c.in_req);
+ channel_refresh_begin(&c->c);
break;
case BGP_GRS_ACTIVE:
- rt_refresh_end(c->c.table, &c->c.in_req);
- rt_refresh_begin(c->c.table, &c->c.in_req);
+ channel_refresh_end(&c->c);
+ channel_refresh_begin(&c->c);
break;
case BGP_GRS_LLGR:
- rt_refresh_begin(c->c.table, &c->c.in_req);
- rt_modify_stale(c->c.table, &c->c.in_req);
+ channel_refresh_begin(&c->c);
+ bgp_graceful_restart_feed(c);
break;
}
}
else
{
/* Just flush the routes */
- rt_refresh_begin(c->c.table, &c->c.in_req);
- rt_refresh_end(c->c.table, &c->c.in_req);
+ channel_refresh_begin(&c->c);
+ channel_refresh_end(&c->c);
}
/* Reset bucket and prefix tables */
@@ -811,6 +820,50 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
tm_start(p->gr_timer, p->conn->remote_caps->gr_time S);
}
+static void
+bgp_graceful_restart_feed_done(struct rt_export_request *req)
+{
+ req->hook = NULL;
+}
+
+static void
+bgp_graceful_restart_feed_dump_req(struct rt_export_request *req)
+{
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, stale_feed, req);
+ debug(" BGP-GR %s.%s export request %p\n", c->c.proto->name, c->c.name, req);
+}
+
+static void
+bgp_graceful_restart_feed_log_state_change(struct rt_export_request *req, u8 state)
+{
+ struct bgp_channel *c = SKIP_BACK(struct bgp_channel, stale_feed, req);
+ struct bgp_proto *p = (void *) c->c.proto;
+ BGP_TRACE(D_EVENTS, "Long-lived graceful restart export state changed to %s", rt_export_state_name(state));
+
+ if (state == TES_READY)
+ rt_stop_export(req, bgp_graceful_restart_feed_done);
+}
+
+static void
+bgp_graceful_restart_drop_export(struct rt_export_request *req UNUSED, const net_addr *n UNUSED, struct rt_pending_export *rpe UNUSED)
+{ /* Nothing to do */ }
+
+static void
+bgp_graceful_restart_feed(struct bgp_channel *c)
+{
+ c->stale_feed = (struct rt_export_request) {
+ .name = "BGP-GR",
+ .trace_routes = c->c.debug | c->c.proto->debug,
+ .dump_req = bgp_graceful_restart_feed_dump_req,
+ .log_state_change = bgp_graceful_restart_feed_log_state_change,
+ .export_bulk = bgp_rte_modify_stale,
+ .export_one = bgp_graceful_restart_drop_export,
+ };
+
+ rt_request_export(c->c.table, &c->stale_feed);
+}
+
+
/**
* bgp_graceful_restart_done - finish active BGP graceful restart
* @c: BGP channel
@@ -833,8 +886,11 @@ bgp_graceful_restart_done(struct bgp_channel *c)
if (!p->gr_active_num)
BGP_TRACE(D_EVENTS, "Neighbor graceful restart done");
+ if (c->stale_feed.hook)
+ rt_stop_export(&c->stale_feed, bgp_graceful_restart_feed_done);
+
tm_stop(c->stale_timer);
- rt_refresh_end(c->c.table, &c->c.in_req);
+ channel_refresh_end_reload(&c->c);
}
/**
@@ -876,7 +932,7 @@ bgp_graceful_restart_timeout(timer *t)
/* Channel is in GR, and supports LLGR -> start LLGR */
c->gr_active = BGP_GRS_LLGR;
tm_start(c->stale_timer, c->stale_time S);
- rt_modify_stale(c->c.table, &c->c.in_req);
+ bgp_graceful_restart_feed(c);
}
}
else
@@ -914,10 +970,7 @@ bgp_refresh_begin(struct bgp_channel *c)
{ log(L_WARN "%s: BEGIN-OF-RR received before END-OF-RIB, ignoring", p->p.name); return; }
c->load_state = BFS_REFRESHING;
- rt_refresh_begin(c->c.table, &c->c.in_req);
-
- if (c->c.in_table)
- rt_refresh_begin(c->c.in_table, &c->c.in_req);
+ channel_refresh_begin(&c->c);
}
/**
@@ -938,10 +991,7 @@ bgp_refresh_end(struct bgp_channel *c)
{ log(L_WARN "%s: END-OF-RR received without prior BEGIN-OF-RR, ignoring", p->p.name); return; }
c->load_state = BFS_NONE;
- rt_refresh_end(c->c.table, &c->c.in_req);
-
- if (c->c.in_table)
- rt_prune_sync(c->c.in_table, 0);
+ channel_refresh_end_reload(&c->c);
}
@@ -1408,12 +1458,9 @@ bgp_reload_routes(struct channel *C)
struct bgp_proto *p = (void *) C->proto;
struct bgp_channel *c = (void *) C;
- ASSERT(p->conn && (p->route_refresh || c->c.in_table));
+ ASSERT(p->conn && (p->route_refresh));
- if (c->c.in_table)
- channel_schedule_reload(C);
- else
- bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
+ bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
}
static void
@@ -1693,7 +1740,6 @@ bgp_init(struct proto_config *CF)
P->rte_better = bgp_rte_better;
P->rte_mergable = bgp_rte_mergable;
P->rte_recalculate = cf->deterministic_med ? bgp_rte_recalculate : NULL;
- P->rte_modify = bgp_rte_modify_stale;
P->rte_igp_metric = bgp_rte_igp_metric;
p->cf = cf;
@@ -1756,7 +1802,7 @@ bgp_channel_start(struct channel *C)
bgp_init_prefix_table(c);
if (c->cf->import_table)
- channel_setup_in_table(C);
+ channel_setup_in_table(C, 0);
if (c->cf->export_table)
channel_setup_out_table(C);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index c79dd1b2..342dc023 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -366,6 +366,7 @@ struct bgp_channel {
timer *stale_timer; /* Long-lived stale timer for LLGR */
u32 stale_time; /* Stored LLGR stale time from last session */
+ struct rt_export_request stale_feed; /* Feeder request for stale route modification */
u8 add_path_rx; /* Session expects receive of ADD-PATH extended NLRI */
u8 add_path_tx; /* Session expects transmit of ADD-PATH extended NLRI */
@@ -585,7 +586,7 @@ void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
int bgp_rte_better(struct rte *, struct rte *);
int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
-struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
+void bgp_rte_modify_stale(struct rt_export_request *, const net_addr *, struct rt_pending_export *, rte **, uint);
u32 bgp_rte_igp_metric(struct rte *);
void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old);
int bgp_preexport(struct channel *, struct rte *);
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index f1e6d7d2..647551e5 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -2695,7 +2695,7 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, uint len)
{
case BGP_RR_REQUEST:
BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
- rt_refeed_channel(&c->c);
+ channel_request_feeding(&c->c);
break;
case BGP_RR_BEGIN: