extern struct protocol proto_unix_iface;
--static void channel_request_reload(struct channel *c);
-static void proto_shutdown_loop(timer *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
-static void channel_verify_limits(struct channel *c);
-static inline void channel_reset_limit(struct channel_limit *l);
-
+static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
+static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
+static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
+static int channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n);
+static int channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n);
+static void channel_feed_end(struct channel *c);
+static void channel_stop_export(struct channel *c);
+static void channel_export_stopped(struct rt_export_request *req);
+static void channel_refeed_stopped(struct rt_export_request *req);
+static void channel_check_stopped(struct channel *c);
+static void channel_reload_in_done(struct channel_import_request *cir);
+static void channel_request_partial_reload(struct channel *c, struct channel_import_request *cir);
static inline int proto_is_done(struct proto *p)
-{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
+{ return (p->proto_state == PS_DOWN) && proto_is_inactive(p); }
static inline int channel_is_active(struct channel *c)
-{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
+{ return (c->channel_state != CS_DOWN); }
static inline int channel_reloadable(struct channel *c)
{ return c->proto->reload_routes && c->reloadable; }
}
static void
- static void
+channel_import_request_done_dynamic(struct channel_import_request *req)
+{
+ mb_free(req);
+}
+
++void
channel_request_reload(struct channel *c)
{
- ASSERT(c->channel_state == CS_UP);
+ ASSERT(c->in_req.hook);
ASSERT(channel_reloadable(c));
CD(c, "Reload requested");
static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
-static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
+static inline void channel_close(struct channel *c) { channel_set_state(c, CS_STOP); }
+
+struct channel_feeding_request {
+ struct channel_feeding_request *next; /* Next in request chain */
+ void (*done)(struct channel_feeding_request *); /* Called when refeed finishes */
+ const struct f_trie *trie; /* Reload only matching nets */
+ PACKED enum channel_feeding_request_type {
+ CFRT_DIRECT = 1, /* Refeed by export restart */
+ CFRT_AUXILIARY, /* Refeed by auxiliary request */
+ } type;
+ PACKED enum {
+ CFRS_INACTIVE = 0, /* Inactive request */
+ CFRS_PENDING, /* Request enqueued, do not touch */
+ CFRS_RUNNING, /* Request active, do not touch */
+ } state;
+};
-void channel_request_feeding(struct channel *c);
-void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
-void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
-int channel_reconfigure(struct channel *c, struct channel_config *cf);
+struct channel *channel_from_export_request(struct rt_export_request *req);
+void channel_request_feeding(struct channel *c, struct channel_feeding_request *);
+void channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type);
+static inline int channel_net_is_refeeding(struct channel *c, const net_addr *n)
+{
+ /* Not refeeding if not refeeding at all */
+ if (!c->refeeding || !c->refeed_trie)
+ return 0;
-/* Moved from route.h to avoid dependency conflicts */
-static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }
+ /* Not refeeding if already refed */
+ if (trie_match_net(c->refeed_trie, n))
+ return 0;
-static inline void
-rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
-{
- if (c->in_table && !rte_update_in(c, n, new, src))
- return;
+ /* Refeeding if matching any request */
+ for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next)
+ if (!cfr->trie || trie_match_net(cfr->trie, n))
+ return 1;
- rte_update2(c, n, new, src);
+ /* Not matching any request */
+ return 0;
}
+static inline void channel_net_mark_refed(struct channel *c, const net_addr *n)
+{
+ ASSERT_DIE(c->refeeding && c->refeed_trie);
+ trie_add_prefix(c->refeed_trie, n, n->pxlen, n->pxlen);
+}
+
++void channel_request_reload(struct channel *c);
+
+void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
+void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
+int channel_reconfigure(struct channel *c, struct channel_config *cf);
#endif
struct bgp_proto *p = (void *) C->proto;
struct bgp_channel *c = (void *) C;
- if ((c->desc->mpls) && (p->route_refresh || c->c.in_table))
- bgp_reload_routes(&c->c);
+ /* For MPLS channel, reload all MPLS-aware channels */
+ if (C == p->p.mpls_channel)
+ {
+ BGP_WALK_CHANNELS(p, c)
- return;
++ if ((c->desc->mpls) && (p->route_refresh || c->cf->import_table))
++ channel_request_reload(&c->c);
+
++ /* Ignoring CIR, reloading always everything */
++ cir->done(cir);
++ return 1;
+ }
+
/* Ignore non-BGP channels */
- if (C->channel != &channel_bgp)
- return;
+ if (C->class != &channel_bgp)
+ {
+ cir->done(cir);
+ return 1;
+ }
- ASSERT(p->conn && (p->route_refresh || c->c.in_table));
+ if (cir->trie)
+ {
+ cir->done(cir);
+ return 0;
+ }
+ /* We do not need cir anymore and later we will not be able to detect when to free it. */
+ cir->done(cir);
- if (c->c.in_table)
- channel_schedule_reload(C);
- else
- bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
+ ASSERT(p->conn && p->route_refresh);
+ bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
+ return 1;
}
static void
break;
case NET_MPLS:
- /* FIXME */
- channel_request_feeding(p->ip4_channel);
- channel_request_feeding(p->ip6_channel);
- break;
++ /* MPLS doesn't support partial refeed, always do a full one. */
++ channel_request_feeding_dynamic(p->ip4_channel, CFRT_DIRECT);
++ channel_request_feeding_dynamic(p->ip6_channel, CFRT_DIRECT);
++ cir->done(cir);
+ return 1;
}
-}
-static inline u32
-l3vpn_metric(rte *e)
-{
- u32 metric = ea_get_int(e->attrs->eattrs, EA_GEN_IGP_METRIC, e->attrs->igp_metric);
- return MIN(metric, IGP_METRIC_UNKNOWN);
+ if (cir->trie)
+ {
+ struct import_to_export_reload *reload = lp_alloc(cir->trie->lp, sizeof *reload);
+ *reload = (struct import_to_export_reload) {
+ .cir = cir,
+ .cfr = {
+ .type = CFRT_AUXILIARY,
+ .done = pipe_import_by_refeed_free,
+ .trie = cir->trie,
+ },
+ };
+ channel_request_feeding(feed, &reload->cfr);
+ }
+ else
+ {
+ /* Route reload on one channel is just refeed on the other */
+ channel_request_feeding_dynamic(feed, CFRT_DIRECT);
+ cir->done(cir);
+ }
+
+ return 1;
}
static int