p->active = 0;
proto_log_state_change(p);
+
proto_rethink_goal(p);
}
return 1;
}
+static struct protos_commit_request {
+ struct config *new;
+ struct config *old;
+ enum protocol_startup phase;
+ int force_reconfig;
+ int type;
+} protos_commit_request;
+
+static int proto_rethink_goal_pending = 0;
+
+static void protos_do_commit(struct config *new, struct config *old, int force_reconfig, int type);
+
/**
* protos_commit - commit new protocol configuration
* @new: new configuration
void
protos_commit(struct config *new, struct config *old, int force_reconfig, int type)
{
+ protos_commit_request = (struct protos_commit_request) {
+ .new = new,
+ .old = old,
+ .phase = (new->shutdown && !new->gr_down) ? PROTOCOL_STARTUP_REGULAR : PROTOCOL_STARTUP_NECESSARY,
+ .force_reconfig = force_reconfig,
+ .type = type,
+ };
+
+ protos_do_commit(new, old, force_reconfig, type);
+}
+
+static void
+protos_do_commit(struct config *new, struct config *old, int force_reconfig, int type)
+{
+ enum protocol_startup phase = protos_commit_request.phase;
struct proto_config *oc, *nc;
struct symbol *sym;
struct proto *p;
+ if ((phase < PROTOCOL_STARTUP_REGULAR) || (phase > PROTOCOL_STARTUP_NECESSARY))
+ {
+ protos_commit_request = (struct protos_commit_request) {};
+ return;
+ }
+
DBG("protos_commit:\n");
if (old)
{
WALK_LIST(oc, old->protos)
{
+ if (oc->protocol->startup != phase)
+ continue;
+
p = oc->proto;
sym = cf_find_symbol(new, oc->name);
}
}
- struct proto *first_dev_proto = NULL;
struct proto *after = NULL;
WALK_LIST(nc, new->protos)
- if (!nc->proto)
+ if ((nc->protocol->startup == phase) && !nc->proto)
{
/* Not a first-time configuration */
if (old)
p = proto_init(nc, after);
after = p;
- if (p->proto == &proto_unix_iface)
- first_dev_proto = p;
+ proto_rethink_goal(p);
}
else
after = nc->proto;
DBG("Protocol start\n");
- /* Start device protocol first */
- if (first_dev_proto)
- proto_rethink_goal(first_dev_proto);
-
/* Determine router ID for the first time - it has to be here and not in
global_commit() because it is postponed after start of device protocol */
if (!config->router_id)
die("Cannot determine router ID, please configure it manually");
}
- /* Start all new protocols */
- WALK_TLIST_DELSAFE(proto, p, &global_proto_list)
- proto_rethink_goal(p);
+ /* Commit next round of protocols */
+ if (new->shutdown && !new->gr_down)
+ protos_commit_request.phase++;
+ else
+ protos_commit_request.phase--;
+
+ /* If something is pending, the next round will be called asynchronously from proto_rethink_goal(). */
+ if (!proto_rethink_goal_pending)
+ protos_do_commit(new, old, force_reconfig, type);
}
static void
DBG("Kicking %s down\n", p->name);
PD(p, "Shutting down");
proto_notify_state(p, (p->proto->shutdown ? p->proto->shutdown(p) : PS_DOWN));
+ if (p->reconfiguring)
+ {
+ proto_rethink_goal_pending++;
+ p->reconfiguring = 2;
+ }
}
}
static void
proto_rethink_goal(struct proto *p)
{
+ int goal_pending = (p->reconfiguring == 2);
+
if (p->reconfiguring && !p->active)
{
struct proto_config *nc = p->cf_new;
mb_free(p->message);
mb_free(p);
if (!nc)
- return;
+ goto done;
+
p = proto_init(nc, after);
}
}
else if (!p->active)
proto_start(p);
+
+done:
+ if (goal_pending && !--proto_rethink_goal_pending)
+ protos_do_commit(
+ protos_commit_request.new,
+ protos_commit_request.old,
+ protos_commit_request.force_reconfig,
+ protos_commit_request.type
+ );
}
struct proto *
*/
+enum protocol_startup {
+ PROTOCOL_STARTUP_REGULAR = 0, /* Regular network routing protocol, start last */
+ PROTOCOL_STARTUP_GENERATOR = 1, /* Static route generator, start ahead of regulars */
+ PROTOCOL_STARTUP_CONNECTOR = 2, /* Data connector, start first */
+ PROTOCOL_STARTUP_NECESSARY = 3, /* Vital auxiliary data, start zeroth */
+};
+
struct protocol {
node n;
char *name;
char *template; /* Template for automatic generation of names */
int name_counter; /* Counter for automatic name generation */
uint preference; /* Default protocol preference */
+ enum protocol_startup startup; /* When to start / stop this protocol */
uint channel_mask; /* Mask of accepted channel types (NB_*) */
uint proto_size; /* Size of protocol data structure */
uint config_size; /* Size of protocol config data structure */
.template = "device%d",
.proto_size = sizeof(struct kif_proto),
.config_size = sizeof(struct kif_config),
+ .startup = PROTOCOL_STARTUP_NECESSARY,
.preconfig = kif_preconfig,
.init = kif_init,
.start = kif_start,
.channel_mask = NB_IP | MAYBE_IP6_SADR | MAYBE_MPLS,
.proto_size = sizeof(struct krt_proto),
.config_size = sizeof(struct krt_config),
+ .startup = PROTOCOL_STARTUP_CONNECTOR,
.preconfig = krt_preconfig,
.postconfig = krt_postconfig,
.init = krt_init,