Merge pull request #66 from ifupdown-ng/feature/refcounting
refcounting
This commit is contained in:
commit
277ecaf78a
13 changed files with 240 additions and 42 deletions
|
@ -63,7 +63,7 @@ print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, st
|
|||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_up)
|
||||
if (iface->refcount > 0)
|
||||
return;
|
||||
|
||||
if (parent != NULL)
|
||||
|
@ -87,7 +87,7 @@ print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, st
|
|||
struct lif_interface *child_if = lif_interface_collection_find(collection, tokenp);
|
||||
|
||||
print_interface_dot(collection, child_if, iface);
|
||||
child_if->is_up = true;
|
||||
child_if->refcount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,8 @@ list_state(struct lif_dict *state, struct match_options *opts)
|
|||
fnmatch(opts->include_pattern, entry->key, 0))
|
||||
continue;
|
||||
|
||||
printf("%s=%s\n", entry->key, (const char *) entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
printf("%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,29 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
|||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
skip_interface(struct lif_interface *iface, const char *ifname)
|
||||
{
|
||||
if (exec_opts.force)
|
||||
return false;
|
||||
|
||||
if (up && iface->refcount > 0)
|
||||
{
|
||||
fprintf(stderr, "%s: skipping %s (already configured), use --force to force configuration\n",
|
||||
argv0, ifname);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!up && iface->refcount == 0)
|
||||
{
|
||||
fprintf(stderr, "%s: skipping %s (already deconfigured), use --force to force deconfiguration\n",
|
||||
argv0, ifname);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname)
|
||||
{
|
||||
|
@ -104,6 +127,14 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
|||
return false;
|
||||
}
|
||||
|
||||
if (skip_interface(iface, ifname))
|
||||
{
|
||||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exec_opts.verbose)
|
||||
{
|
||||
fprintf(stderr, "%s: changing state of interface %s to '%s'\n",
|
||||
|
@ -155,6 +186,27 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
|
|||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
update_state_file_and_exit(int rc, struct lif_dict *state)
|
||||
{
|
||||
if (exec_opts.mock)
|
||||
{
|
||||
exit(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!lif_state_write_path(state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not update %s\n", argv0, exec_opts.state_file);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
exit(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
ifupdown_main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -186,9 +238,9 @@ ifupdown_main(int argc, char *argv[])
|
|||
if (match_opts.is_auto)
|
||||
{
|
||||
if (!change_auto_interfaces(&collection, &state, &match_opts))
|
||||
return EXIT_FAILURE;
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return update_state_file_and_exit(EXIT_SUCCESS, &state);
|
||||
}
|
||||
else if (optind >= argc)
|
||||
generic_usage(self_applet, EXIT_FAILURE);
|
||||
|
@ -217,23 +269,17 @@ ifupdown_main(int argc, char *argv[])
|
|||
if (entry == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]);
|
||||
return EXIT_FAILURE;
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
}
|
||||
|
||||
iface = entry->data;
|
||||
}
|
||||
|
||||
if (!change_interface(iface, &collection, &state, ifname))
|
||||
return EXIT_FAILURE;
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
}
|
||||
|
||||
if (!exec_opts.mock && !lif_state_write_path(&state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not update %s\n", argv0, exec_opts.state_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return update_state_file_and_exit(EXIT_SUCCESS, &state);
|
||||
}
|
||||
|
||||
struct if_applet ifup_applet = {
|
||||
|
|
|
@ -68,13 +68,14 @@ set_no_lock(const char *opt_arg)
|
|||
}
|
||||
|
||||
static void
|
||||
no_op(const char *opt_arg)
|
||||
set_force(const char *opt_arg)
|
||||
{
|
||||
(void) opt_arg;
|
||||
exec_opts.force = true;
|
||||
}
|
||||
|
||||
static struct if_option exec_options[] = {
|
||||
{'f', "force", NULL, "force (de)configuration", false, no_op},
|
||||
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
||||
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
||||
{'l', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, set_no_lock},
|
||||
{'n', "no-act", NULL, "do not actually run any commands", false, set_no_act},
|
||||
|
|
|
@ -23,6 +23,7 @@ struct lif_execute_opts {
|
|||
bool verbose;
|
||||
bool mock;
|
||||
bool no_lock;
|
||||
bool force;
|
||||
const char *executor_path;
|
||||
const char *interfaces_file;
|
||||
const char *state_file;
|
||||
|
|
|
@ -53,7 +53,7 @@ struct lif_interface {
|
|||
|
||||
struct lif_dict vars;
|
||||
|
||||
bool is_up;
|
||||
size_t refcount; /* >= 0 if up, else 0 */
|
||||
};
|
||||
|
||||
#define LIF_INTERFACE_COLLECTION_FOREACH(iter, collection) \
|
||||
|
|
|
@ -261,6 +261,36 @@ handle_error:
|
|||
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);
|
||||
|
||||
#ifdef DEBUG_REFCOUNTING
|
||||
fprintf(stderr, "handle_refcounting(): orig_refcount=%zu, refcount=%zu, direction=%s\n",
|
||||
orig_refcount, iface->refcount, up ? "UP" : "DOWN");
|
||||
#endif
|
||||
|
||||
/* if going up and orig_refcount > 0 -- we're already configured. */
|
||||
if (up && orig_refcount > 0)
|
||||
return true;
|
||||
|
||||
/* if going down and iface->refcount > 1 -- we still have other dependents. */
|
||||
if (!up && iface->refcount > 1)
|
||||
return true;
|
||||
|
||||
/* we can change this interface -- no blocking dependents. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up)
|
||||
{
|
||||
|
@ -278,12 +308,17 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
|||
{
|
||||
struct lif_interface *iface = lif_interface_collection_find(collection, tokenp);
|
||||
|
||||
/* already up or down, skip */
|
||||
if (up == iface->is_up)
|
||||
/* if handle_refcounting returns true, it means we've already
|
||||
* configured the interface, or it is too soon to deconfigure
|
||||
* the interface.
|
||||
*/
|
||||
if (handle_refcounting(state, iface, up))
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s)\n",
|
||||
iface->ifname, parent->ifname);
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- %s\n",
|
||||
iface->ifname, parent->ifname,
|
||||
up ? "already configured" : "transient dependencies still exist");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -328,7 +363,7 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
|||
|
||||
lif_state_upsert(state, lifname, iface);
|
||||
|
||||
iface->is_up = true;
|
||||
lif_state_ref_if(state, lifname, iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -345,9 +380,7 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
|||
if (!handle_dependents(opts, iface, collection, state, up))
|
||||
return false;
|
||||
|
||||
lif_state_delete(state, lifname);
|
||||
|
||||
iface->is_up = false;
|
||||
lif_state_unref_if(state, lifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -13,27 +13,41 @@
|
|||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/state.h"
|
||||
#include "libifupdown/fgetline.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
|
||||
bool
|
||||
lif_state_read(struct lif_dict *state, FILE *fd)
|
||||
{
|
||||
char linebuf[4096];
|
||||
|
||||
while (lif_fgetline(linebuf, sizeof linebuf, fd))
|
||||
{
|
||||
char *ifname = linebuf;
|
||||
char *bufp = linebuf;
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
char *refcount = lif_next_token(&bufp);
|
||||
size_t rc = 1;
|
||||
char *equals_p = strchr(linebuf, '=');
|
||||
|
||||
if (*refcount)
|
||||
{
|
||||
rc = strtoul(refcount, NULL, 10);
|
||||
|
||||
if (rc == 0 || rc == ULONG_MAX)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if (equals_p == NULL)
|
||||
{
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc });
|
||||
continue;
|
||||
}
|
||||
|
||||
*equals_p++ = '\0';
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc });
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -55,10 +69,38 @@ lif_state_read_path(struct lif_dict *state, const char *path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
iface->refcount++;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
if (iface->refcount == 0)
|
||||
return;
|
||||
|
||||
iface->refcount--;
|
||||
|
||||
if (iface->refcount)
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
else
|
||||
lif_state_delete(state, ifname);
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
lif_dict_add(state, ifname, strdup(iface->ifname));
|
||||
lif_state_delete(state, ifname);
|
||||
|
||||
struct lif_state_record *rec = calloc(1, sizeof(*rec));
|
||||
|
||||
rec->mapped_if = strdup(iface->ifname);
|
||||
rec->refcount = iface->refcount;
|
||||
|
||||
lif_dict_add(state, ifname, rec);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -69,7 +111,10 @@ lif_state_delete(struct lif_dict *state, const char *ifname)
|
|||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
free(entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
free(rec->mapped_if);
|
||||
free(rec);
|
||||
|
||||
lif_dict_delete_entry(state, entry);
|
||||
}
|
||||
|
||||
|
@ -81,8 +126,9 @@ lif_state_write(const struct lif_dict *state, FILE *f)
|
|||
LIF_DICT_FOREACH(iter, state)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_state_record *rec = entry->data;
|
||||
|
||||
fprintf(f, "%s=%s\n", entry->key, (const char *) entry->data);
|
||||
fprintf(f, "%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +154,8 @@ lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const c
|
|||
if (entry == NULL)
|
||||
return NULL;
|
||||
|
||||
struct lif_dict_entry *if_entry = lif_dict_find(if_collection, (const char *) entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
struct lif_dict_entry *if_entry = lif_dict_find(if_collection, rec->mapped_if);
|
||||
|
||||
if (if_entry == NULL)
|
||||
return NULL;
|
||||
|
@ -124,9 +171,10 @@ lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection)
|
|||
LIF_DICT_FOREACH(iter, state)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *iface = lif_interface_collection_find(if_collection, entry->key);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if);
|
||||
|
||||
iface->is_up = true;
|
||||
iface->refcount = rec->refcount;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -19,9 +19,16 @@
|
|||
#include <stdio.h>
|
||||
#include "libifupdown/interface.h"
|
||||
|
||||
struct lif_state_record {
|
||||
char *mapped_if;
|
||||
size_t refcount;
|
||||
};
|
||||
|
||||
extern bool lif_state_read(struct lif_dict *state, FILE *f);
|
||||
extern bool lif_state_read_path(struct lif_dict *state, const char *path);
|
||||
extern void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_delete(struct lif_dict *state, const char *ifname);
|
||||
extern void lif_state_write(const struct lif_dict *state, FILE *f);
|
||||
extern bool lif_state_write_path(const struct lif_dict *state, const char *path);
|
||||
|
|
6
tests/fixtures/deferred-teardown-1.ifstate
vendored
Normal file
6
tests/fixtures/deferred-teardown-1.ifstate
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
lo=lo 1
|
||||
br0=br0 1
|
||||
bond0=bond0 2
|
||||
eth0=eth0 3
|
||||
eth1=eth1 2
|
||||
tun0=tun0 1
|
9
tests/fixtures/deferred-teardown-1.interfaces
vendored
Normal file
9
tests/fixtures/deferred-teardown-1.interfaces
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
auto br0
|
||||
iface br0
|
||||
requires bond0
|
||||
|
||||
iface bond0
|
||||
requires eth0 eth1
|
||||
|
||||
iface tun0
|
||||
requires eth0
|
5
tests/fixtures/deferred-teardown-2.ifstate
vendored
Normal file
5
tests/fixtures/deferred-teardown-2.ifstate
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
eth0=eth0 5
|
||||
tun0=tun0 1
|
||||
tun1=tun1 1
|
||||
tun2=tun2 1
|
||||
tun3=tun3 1
|
11
tests/fixtures/deferred-teardown-2.interfaces
vendored
Normal file
11
tests/fixtures/deferred-teardown-2.interfaces
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
iface tun0
|
||||
requires eth0
|
||||
|
||||
iface tun1
|
||||
requires eth0
|
||||
|
||||
iface tun2
|
||||
requires eth0
|
||||
|
||||
iface tun3
|
||||
requires eth0
|
|
@ -19,6 +19,9 @@ tests_init \
|
|||
learned_dependency_2 \
|
||||
learned_executor \
|
||||
implicit_vlan \
|
||||
deferred_teardown_1 \
|
||||
deferred_teardown_2 \
|
||||
deferred_teardown_3 \
|
||||
regress_opt_f
|
||||
|
||||
noargs_body() {
|
||||
|
@ -27,56 +30,56 @@ noargs_body() {
|
|||
|
||||
lo_always_auto_body() {
|
||||
atf_check -s exit:0 -e ignore -o match:'executors/link' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i/dev/null -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i/dev/null -n -a
|
||||
}
|
||||
|
||||
dual_stack_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/static' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0.interfaces -n -a
|
||||
}
|
||||
|
||||
static_ipv4_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/static' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4.interfaces -n -a
|
||||
}
|
||||
|
||||
static_ipv4_netmask_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/static' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4-netmask.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4-netmask.interfaces -n -a
|
||||
}
|
||||
|
||||
static_ipv6_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/static' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6.interfaces -n -a
|
||||
}
|
||||
|
||||
static_ipv6_netmask_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/static' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6-netmask.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6-netmask.interfaces -n -a
|
||||
}
|
||||
|
||||
inet_dhcp_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/dhcp' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/dhcp-eth0.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/dhcp-eth0.interfaces -n -a
|
||||
}
|
||||
|
||||
use_dhcp_body() {
|
||||
atf_check -s exit:0 -e ignore \
|
||||
-o match:'executors/link' \
|
||||
-o match:'executors/dhcp' \
|
||||
ifdown -S/dev/null -E $EXECUTORS -i $FIXTURES/use-dhcp-eth0.interfaces -n -a
|
||||
ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/use-dhcp-eth0.interfaces -n -a
|
||||
}
|
||||
|
||||
alias_eth0_home_body() {
|
||||
|
@ -142,6 +145,33 @@ implicit_vlan_body() {
|
|||
ifdown -n -S $FIXTURES/vlan.ifstate -E $EXECUTORS -i $FIXTURES/vlan.interfaces eth0.8
|
||||
}
|
||||
|
||||
deferred_teardown_1_body() {
|
||||
atf_check -s exit:0 -o ignore \
|
||||
-e match:"skipping dependent interface eth0 \\(of bond0\\) -- transient dependencies still exist" \
|
||||
-e match:"changing state of dependent interface eth1 \\(of bond0\\) to down" \
|
||||
ifdown -n -S $FIXTURES/deferred-teardown-1.ifstate -E $EXECUTORS \
|
||||
-i $FIXTURES/deferred-teardown-1.interfaces br0
|
||||
}
|
||||
|
||||
deferred_teardown_2_body() {
|
||||
atf_check -s exit:0 -o ignore \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun0\\) -- transient dependencies still exist" \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun1\\) -- transient dependencies still exist" \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun2\\) -- transient dependencies still exist" \
|
||||
ifdown -n -S $FIXTURES/deferred-teardown-2.ifstate -E $EXECUTORS \
|
||||
-i $FIXTURES/deferred-teardown-2.interfaces tun0 tun1 tun2
|
||||
}
|
||||
|
||||
deferred_teardown_3_body() {
|
||||
atf_check -s exit:0 -o ignore \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun0\\) -- transient dependencies still exist" \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun1\\) -- transient dependencies still exist" \
|
||||
-e match:"skipping dependent interface eth0 \\(of tun2\\) -- transient dependencies still exist" \
|
||||
-e match:"changing state of dependent interface eth0 \\(of tun3\\) to down" \
|
||||
ifdown -n -S $FIXTURES/deferred-teardown-2.ifstate -E $EXECUTORS \
|
||||
-i $FIXTURES/deferred-teardown-2.interfaces tun0 tun1 tun2 tun3
|
||||
}
|
||||
|
||||
regress_opt_f_body() {
|
||||
atf_check -s exit:0 -o ignore -e ignore \
|
||||
ifdown -n -S $FIXTURES/vlan.ifstate -E $EXECUTORS -i $FIXTURES/vlan.interfaces -f eth0.8
|
||||
|
|
Loading…
Reference in a new issue