lifecycle: use refcounting to defer interface teardown
This commit is contained in:
parent
288976f015
commit
6603ff1000
2 changed files with 39 additions and 8 deletions
|
@ -261,6 +261,31 @@ handle_error:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function returns true if we can skip processing the interface for now,
|
||||||
|
* otherwise false.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
handle_refcounting(struct lif_dict *state, struct lif_interface *iface, bool up)
|
||||||
|
{
|
||||||
|
size_t orig_refcount = iface->refcount;
|
||||||
|
|
||||||
|
if (up)
|
||||||
|
lif_state_ref_if(state, iface->ifname, iface);
|
||||||
|
else
|
||||||
|
lif_state_unref_if(state, iface->ifname, iface);
|
||||||
|
|
||||||
|
/* if going up and orig_refcount > 0 -- we're already configured. */
|
||||||
|
if (up && orig_refcount > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* if going down and iface->refcount > 0 -- we still have other dependents. */
|
||||||
|
if (!up && iface->refcount > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* we can change this interface -- no blocking dependents. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up)
|
handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up)
|
||||||
{
|
{
|
||||||
|
@ -278,12 +303,17 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
||||||
{
|
{
|
||||||
struct lif_interface *iface = lif_interface_collection_find(collection, tokenp);
|
struct lif_interface *iface = lif_interface_collection_find(collection, tokenp);
|
||||||
|
|
||||||
/* already up or down, skip */
|
/* if handle_refcounting returns true, it means we've already
|
||||||
if (up && iface->refcount > 0)
|
* configured the interface, or it is too soon to deconfigure
|
||||||
|
* the interface.
|
||||||
|
*/
|
||||||
|
if (handle_refcounting(state, iface, up))
|
||||||
{
|
{
|
||||||
if (opts->verbose)
|
if (opts->verbose)
|
||||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s)\n",
|
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- %s\n",
|
||||||
iface->ifname, parent->ifname);
|
iface->ifname, parent->ifname,
|
||||||
|
up ? "already configured" : "transient dependencies still exist");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +358,7 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
||||||
|
|
||||||
lif_state_upsert(state, lifname, iface);
|
lif_state_upsert(state, lifname, iface);
|
||||||
|
|
||||||
iface->refcount++;
|
lif_state_ref_if(state, lifname, iface);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -345,9 +375,7 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
||||||
if (!handle_dependents(opts, iface, collection, state, up))
|
if (!handle_dependents(opts, iface, collection, state, up))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lif_state_delete(state, lifname);
|
lif_state_unref_if(state, lifname, iface);
|
||||||
|
|
||||||
iface->refcount--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -73,6 +73,9 @@ lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interfac
|
||||||
void
|
void
|
||||||
lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||||
{
|
{
|
||||||
|
if (iface->refcount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
iface->refcount--;
|
iface->refcount--;
|
||||||
|
|
||||||
if (iface->refcount)
|
if (iface->refcount)
|
||||||
|
|
Loading…
Reference in a new issue