lifecycle: use refcounting to defer interface teardown

This commit is contained in:
Ariadne Conill 2020-09-08 15:28:36 -06:00
parent 288976f015
commit 6603ff1000
2 changed files with 39 additions and 8 deletions

View file

@ -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;

View file

@ -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)