diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/proto.c | 32 | ||||
-rw-r--r-- | nest/protocol.h | 3 | ||||
-rw-r--r-- | nest/route.h | 3 | ||||
-rw-r--r-- | nest/rt-table.c | 97 |
4 files changed, 99 insertions, 36 deletions
diff --git a/nest/proto.c b/nest/proto.c index e81aadc..76467aa 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -410,6 +410,25 @@ proto_fell_down(struct proto *p) } static void +proto_feed_more(void *P) +{ + struct proto *p = P; + + DBG("Feeding protocol %s continued\n", p->name); + if (rt_feed_baby(p)) + { + p->core_state = FS_HAPPY; + proto_relink(p); + DBG("Protocol %s up and running\n", p->name); + } + else + { + p->attn->hook = proto_feed_more; + ev_schedule(p->attn); /* Will continue later... */ + } +} + +static void proto_feed(void *P) { struct proto *p = P; @@ -417,10 +436,7 @@ proto_feed(void *P) DBG("Feeding protocol %s\n", p->name); proto_add_announce_hook(p, p->table); if_feed_baby(p); - rt_feed_baby(p); - p->core_state = FS_HAPPY; - proto_relink(p); - DBG("Protocol %s up and running\n", p->name); + proto_feed_more(P); } void @@ -444,8 +460,12 @@ proto_notify_state(struct proto *p, unsigned ps) } else if (cs == FS_FLUSHING) /* Still flushing... */ ; - else /* Need to start flushing */ - goto schedule_flush; + else + { + if (cs == FS_FEEDING) /* Need to abort feeding */ + rt_feed_baby_abort(p); + goto schedule_flush; /* Need to start flushing */ + } break; case PS_START: ASSERT(ops == PS_DOWN); diff --git a/nest/protocol.h b/nest/protocol.h index df9064b..64ea466 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -151,6 +151,9 @@ struct proto { struct filter *out_filter; /* Output filter */ struct announce_hook *ahooks; /* Announcement hooks for this protocol */ + struct fib_iterator *feed_iterator; /* Routing table iterator used during protocol feeding */ + struct announce_hook *feed_ahook; /* Announce hook we currently feed */ + /* Hic sunt protocol-specific data */ }; diff --git a/nest/route.h b/nest/route.h index 20709e9..183e80b 100644 --- a/nest/route.h +++ b/nest/route.h @@ -197,7 +197,8 @@ rte *rte_do_cow(rte *); static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; } void rt_dump(rtable *); void rt_dump_all(void); -void rt_feed_baby(struct proto *p); +int rt_feed_baby(struct proto *p); +void rt_feed_baby_abort(struct proto *p); void rt_prune(rtable *tab); void rt_prune_all(void); struct rtable_config *rt_new_table(struct symbol *s); diff --git a/nest/rt-table.c b/nest/rt-table.c index 7133ed4..d81dd85 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -200,35 +200,6 @@ rte_announce(rtable *tab, net *net, rte *new, rte *old, ea_list *tmpa) } } -void -rt_feed_baby(struct proto *p) -{ - struct announce_hook *h; - - if (!p->ahooks) - return; - DBG("Announcing routes to new protocol %s\n", p->name); - for(h=p->ahooks; h; h=h->next) - { - rtable *t = h->table; - FIB_WALK(&t->fib, fn) - { - net *n = (net *) fn; - rte *e; - for(e=n->routes; e; e=e->next) - { - struct proto *q = e->attrs->proto; - ea_list *tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; - do_rte_announce(h, n, e, NULL, tmpa, ipa_classify(n->n.prefix)); - lp_flush(rte_update_pool); - if (p->core_state != FS_FEEDING) - return; /* In the meantime, the protocol fell down. */ - } - } - FIB_WALK_END; - } -} - static inline int rte_validate(rte *e) { @@ -683,6 +654,74 @@ rt_commit(struct config *new, struct config *old) DBG("\tdone\n"); } +int +rt_feed_baby(struct proto *p) +{ + struct announce_hook *h; + struct fib_iterator *fit; + int max_feed = 2; /* FIXME */ + + if (!p->feed_ahook) /* Need to initialize first */ + { + if (!p->ahooks) + return 1; + DBG("Announcing routes to new protocol %s\n", p->name); + p->feed_ahook = p->ahooks; + fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator)); + goto next_hook; + } + fit = p->feed_iterator; + +again: + h = p->feed_ahook; + FIB_ITERATE_START(&h->table->fib, fit, fn) + { + net *n = (net *) fn; + rte *e; + for(e=n->routes; e; e=e->next) + { + struct proto *q = e->attrs->proto; + ea_list *tmpa; + + if (p->core_state != FS_FEEDING) + return 1; /* In the meantime, the protocol fell down. */ + rte_update_lock(); + tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL; + do_rte_announce(h, n, e, NULL, tmpa, ipa_classify(n->n.prefix)); + rte_update_unlock(); + if (!--max_feed) + { + FIB_ITERATE_PUT(fit, fn); + return 0; + } + } + } + FIB_ITERATE_END(fn); + p->feed_ahook = h->next; + if (!p->feed_ahook) + { + mb_free(p->feed_iterator); + p->feed_iterator = NULL; + return 1; + } + +next_hook: + h = p->feed_ahook; + FIB_ITERATE_INIT(fit, &h->table->fib); + goto again; +} + +void +rt_feed_baby_abort(struct proto *p) +{ + if (p->feed_ahook) + { + /* Unlink the iterator and exit */ + fit_get(&p->feed_ahook->table->fib, p->feed_iterator); + p->feed_ahook = NULL; + } +} + /* * CLI commands */ |