From: Jan Moskyto Matejka Date: Fri, 8 Apr 2016 10:09:31 +0000 (+0200) Subject: Merge branch 'master' into int-new-channels X-Git-Tag: v2.0.0-pre0~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a7ac656829223713f9e6bcef63d2b5a5efce7d2;p=thirdparty%2Fbird.git Merge branch 'master' into int-new-channels --- 7a7ac656829223713f9e6bcef63d2b5a5efce7d2 diff --cc filter/config.Y index 3bb00c13d,b94f5dfff..3e70a63e5 --- a/filter/config.Y +++ b/filter/config.Y @@@ -282,7 -283,8 +282,7 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN LEN, DEFINED, ADD, DELETE, CONTAINS, RESET, - PREPEND, FIRST, LAST, MATCH, + PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, - ROA_CHECK, EMPTY, FILTER, WHERE, EVAL) diff --cc nest/config.Y index 6bb686c3b,87827c10d..94a676705 --- a/nest/config.Y +++ b/nest/config.Y @@@ -109,10 -106,12 +109,10 @@@ idval | SYM { if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD)) $$ = SYM_VAL($1).i; -#ifndef IPV6 - else if ($1->class == (SYM_CONSTANT | T_IP)) - $$ = ipa_to_u32(SYM_VAL($1).px.ip); -#endif + else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip)) + $$ = ipa_to_u32(SYM_VAL($1).ip); else - cf_error("Number of IPv4 address constant expected"); + cf_error("Number or IPv4 address constant expected"); } ; diff --cc nest/proto.c index f712fe5f4,436377f1b..df4952b73 --- a/nest/proto.c +++ b/nest/proto.c @@@ -78,297 -96,95 +78,298 @@@ proto_log_state_change(struct proto *p } -/** - * proto_new - create a new protocol instance - * @c: protocol configuration - * @size: size of protocol data structure (each protocol instance is represented by - * a structure starting with generic part [struct &proto] and continued - * with data specific to the protocol) - * - * When a new configuration has been read in, the core code starts - * initializing all the protocol instances configured by calling their - * init() hooks with the corresponding instance configuration. The initialization - * code of the protocol is expected to create a new instance according to the - * configuration by calling this function and then modifying the default settings - * to values wanted by the protocol. - */ -void * -proto_new(struct proto_config *c, unsigned size) +struct channel_config * +proto_cf_find_channel(struct proto_config *pc, uint net_type) { - struct protocol *pr = c->protocol; - struct proto *p = mb_allocz(proto_pool, size); - - p->cf = c; - p->debug = c->debug; - p->mrtdump = c->mrtdump; - p->name = c->name; - p->preference = c->preference; - p->disabled = c->disabled; - p->proto = pr; - p->table = c->table->table; - p->hash_key = random_u32(); - c->proto = p; - return p; + struct channel_config *cc; + + WALK_LIST(cc, pc->channels) + if (cc->net_type == net_type) + return cc; + + return NULL; } -static void -proto_init_instance(struct proto *p) +/** + * proto_find_channel_by_table - find channel connected to a routing table + * @p: protocol instance + * @t: routing table + * + * Returns pointer to channel or NULL + */ +struct channel * +proto_find_channel_by_table(struct proto *p, struct rtable *t) { - /* Here we cannot use p->cf->name since it won't survive reconfiguration */ - p->pool = rp_new(proto_pool, p->proto->name); - p->attn = ev_new(p->pool); - p->attn->data = p; + struct channel *c; - if (graceful_restart_state == GRS_INIT) - p->gr_recovery = 1; + WALK_LIST(c, p->channels) + if (c->table == t) + return c; - if (! p->proto->multitable) - rt_lock_table(p->table); + return NULL; } -extern pool *rt_table_pool; /** - * proto_add_announce_hook - connect protocol to a routing table + * proto_add_channel - connect protocol to a routing table * @p: protocol instance - * @t: routing table to connect to - * @stats: per-table protocol statistics - * - * This function creates a connection between the protocol instance @p and the - * routing table @t, making the protocol hear all changes in the table. + * @cf: channel configuration * - * The announce hook is linked in the protocol ahook list. Announce hooks are - * allocated from the routing table resource pool and when protocol accepts - * routes also in the table ahook list. The are linked to the table ahook list - * and unlinked from it depending on export_state (in proto_want_export_up() and - * proto_want_export_down()) and they are automatically freed after the protocol - * is flushed (in proto_fell_down()). + * This function creates a channel between the protocol instance @p and the + * routing table specified in the configuration @cf, making the protocol hear + * all changes in the table and allowing the protocol to update routes in the + * table. * - * Unless you want to listen to multiple routing tables (as the Pipe protocol - * does), you needn't to worry about this function since the connection to the - * protocol's primary routing table is initialized automatically by the core - * code. + * The channel is linked in the protocol channel list and when active also in + * the table channel list. Channels are allocated from the global resource pool + * (@proto_pool) and they are automatically freed when the protocol is removed. */ -struct announce_hook * -proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats) + +struct channel * +proto_add_channel(struct proto *p, struct channel_config *cf) +{ + struct channel *c = mb_allocz(proto_pool, cf->channel->channel_size); + + c->name = cf->name; + c->channel = cf->channel; + c->proto = p; + c->table = cf->table->table; + + c->in_filter = cf->in_filter; + c->out_filter = cf->out_filter; + c->rx_limit = cf->rx_limit; + c->in_limit = cf->in_limit; + c->out_limit = cf->out_limit; + + c->net_type = cf->net_type; + c->ra_mode = cf->ra_mode; + c->preference = cf->preference; + c->merge_limit = cf->merge_limit; + c->in_keep_filtered = cf->in_keep_filtered; + + c->channel_state = CS_DOWN; + c->export_state = ES_DOWN; + c->last_state_change = now; + c->reloadable = 1; + + CALL(c->channel->init, c, cf); + + add_tail(&p->channels, &c->n); + + PD(p, "Channel %s connected to table %s", c->name, c->table->name); + + return c; +} + +void +proto_remove_channel(struct proto *p, struct channel *c) +{ + ASSERT(c->channel_state == CS_DOWN); + + PD(p, "Channel %s removed", c->name); + + rem_node(&c->n); + mb_free(c); +} + + +static void +proto_start_channels(struct proto *p) +{ + struct channel *c; + WALK_LIST(c, p->channels) + if (!c->disabled) + channel_set_state(c, CS_UP); +} + +static void +proto_pause_channels(struct proto *p) +{ + struct channel *c; + WALK_LIST(c, p->channels) + if (!c->disabled && channel_is_active(c)) + channel_set_state(c, CS_START); +} + +static void +proto_stop_channels(struct proto *p) +{ + struct channel *c; + WALK_LIST(c, p->channels) + if (!c->disabled && channel_is_active(c)) + channel_set_state(c, CS_FLUSHING); +} + +static void +proto_remove_channels(struct proto *p) +{ + struct channel *c; + WALK_LIST_FIRST(c, p->channels) + proto_remove_channel(p, c); +} + +static void +channel_schedule_feed(struct channel *c, int initial) +{ + // DBG("%s: Scheduling meal\n", p->name); + ASSERT(c->channel_state == CS_UP); + + c->export_state = ES_FEEDING; + c->refeeding = !initial; + + ev_schedule(c->feed_event); +} + +static void +channel_feed_loop(void *ptr) +{ + struct channel *c = ptr; + + if (c->export_state != ES_FEEDING) + return; + + if (!c->feed_active) + if (c->proto->feed_begin) + c->proto->feed_begin(c, !c->refeeding); + + // DBG("Feeding protocol %s continued\n", p->name); + if (!rt_feed_channel(c)) + { + ev_schedule(c->feed_event); + return; + } + + // DBG("Feeding protocol %s finished\n", p->name); + c->export_state = ES_READY; + // proto_log_state_change(p); + + if (c->proto->feed_end) + c->proto->feed_end(c); +} + + +static void +channel_start_export(struct channel *c) +{ + ASSERT(c->channel_state == CS_UP); + ASSERT(c->export_state == ES_DOWN); + + channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ +} + +static void +channel_stop_export(struct channel *c) +{ + /* Need to abort feeding */ + if (c->export_state == ES_FEEDING) + rt_feed_channel_abort(c); + + c->export_state = ES_DOWN; ++ c->stats.exp_routes = 0; +} + +static void +channel_do_start(struct channel *c) { - struct announce_hook *h; + rt_lock_table(c->table); + add_tail(&c->table->channels, &c->table_node); + c->proto->active_channels++; + + c->feed_event = ev_new(c->proto->pool); + c->feed_event->data = c; + c->feed_event->hook = channel_feed_loop; + + channel_reset_limit(&c->rx_limit); + channel_reset_limit(&c->in_limit); + channel_reset_limit(&c->out_limit); + + CALL(c->channel->start, c); +} + +static void +channel_do_flush(struct channel *c) +{ + rt_schedule_prune(c->table); + + c->gr_wait = 0; + if (c->gr_lock) + channel_graceful_restart_unlock(c); + + CALL(c->channel->shutdown, c); +} - DBG("Connecting protocol %s to table %s\n", p->name, t->name); - PD(p, "Connected to table %s", t->name); +static void +channel_do_down(struct channel *c) +{ - rem2_node(&c->table_node); ++ rem_node(&c->table_node); + rt_unlock_table(c->table); + c->proto->active_channels--; - h = mb_allocz(rt_table_pool, sizeof(struct announce_hook)); - h->table = t; - h->proto = p; - h->stats = stats; + if ((c->stats.imp_routes + c->stats.filt_routes) != 0) + log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name); - h->next = p->ahooks; - p->ahooks = h; + memset(&c->stats, 0, sizeof(struct proto_stats)); - if (p->rt_notify && (p->export_state != ES_DOWN)) - add_tail(&t->hooks, &h->n); - return h; + /* Schedule protocol shutddown */ + if (proto_is_done(c->proto)) + ev_schedule(c->proto->event); +} + +void +channel_set_state(struct channel *c, uint state) +{ + uint cs = c->channel_state; + uint es = c->export_state; + + DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, cs_states[cs], cs_states[state]); + if (state == cs) + return; + + c->channel_state = state; + c->last_state_change = now; + + switch (state) + { + case CS_START: + ASSERT(cs == CS_DOWN || cs == CS_UP); + + if (cs == CS_DOWN) + channel_do_start(c); + + if (es != ES_DOWN) + channel_stop_export(c); + + break; + + case CS_UP: + ASSERT(cs == CS_DOWN || cs == CS_START); + + if (cs == CS_DOWN) + channel_do_start(c); + + if (!c->gr_wait && c->proto->rt_notify) + channel_start_export(c); + + break; + + case CS_FLUSHING: + ASSERT(cs == CS_START || cs == CS_UP); + + if (es != ES_DOWN) + channel_stop_export(c); + + channel_do_flush(c); + break; + + case CS_DOWN: + ASSERT(cs == CS_FLUSHING); + + channel_do_down(c); + break; + + default: + ASSERT(0); + } + // XXXX proto_log_state_change(c); } /** diff --cc sysdep/unix/io.c index cbfb47d5d,5955dbfef..37e26c9b8 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@@ -1416,9 -1402,7 +1402,6 @@@ sk_open(sock *s if (fd < 0) ERR("socket"); - if (fd >= FD_SETSIZE) - ERR2("FD_SETSIZE limit reached"); - - s->af = af; s->fd = fd; if (sk_setup(s) < 0) diff --cc sysdep/unix/krt.c index 6b3b4eee0,f5dee8775..b0a966137 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@@ -408,11 -412,18 +408,17 @@@ krt_learn_prune(struct krt_proto *p FIB_ITERATE_INIT(&fit, fib); again: - FIB_ITERATE_START(fib, &fit, f) + FIB_ITERATE_START(fib, &fit, net, n) { - net *n = (net *) f; rte *e, **ee, *best, **pbest, *old_best; - old_best = n->routes; + /* + * Note that old_best may be NULL even if there was an old best route in + * the previous step, because it might be replaced in krt_learn_scan(). + * But in that case there is a new valid best route. + */ + + old_best = NULL; best = NULL; pbest = NULL; ee = &n->routes; @@@ -436,14 -453,14 +448,14 @@@ { DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen); if (old_best) - { - krt_learn_announce_delete(p, n); - n->n.flags &= ~KRF_INSTALLED; - } + krt_learn_announce_delete(p, n); + - FIB_ITERATE_PUT(&fit, f); - fib_delete(fib, f); + FIB_ITERATE_PUT(&fit); + fib_delete(fib, n); goto again; } + + best->u.krt.best = 1; *pbest = best->next; best->next = n->routes; n->routes = best;