Compare commits
20 commits
main
...
ifupdown-n
Author | SHA1 | Date | |
---|---|---|---|
|
975e4f1bea | ||
|
bcf090f7ad | ||
|
f671e2d410 | ||
|
6da55d9299 | ||
|
726a888c8d | ||
|
b425ad75e3 | ||
|
bd730bece4 | ||
|
9e859d458b | ||
|
40c7ed53e1 | ||
|
42836934e9 | ||
|
93dff79567 | ||
|
61da61dfdb | ||
|
e16c24203e | ||
|
ebae949462 | ||
|
0464118429 | ||
|
69999cd357 | ||
|
d92cfdd184 | ||
|
045211514b | ||
|
0d28f94a47 | ||
|
0abafedb9a |
15 changed files with 187 additions and 37 deletions
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ LIBBSD_CFLAGS =
|
|||
LIBBSD_LIBS =
|
||||
|
||||
PACKAGE_NAME := ifupdown-ng
|
||||
PACKAGE_VERSION := 0.10.0
|
||||
PACKAGE_VERSION := 0.10.2
|
||||
PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new
|
||||
|
||||
|
||||
|
|
|
@ -182,7 +182,8 @@ list_state(struct lif_dict *state, struct match_options *opts)
|
|||
if (listing_running)
|
||||
printf("%s\n", entry->key);
|
||||
else
|
||||
printf("%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
||||
printf("%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||
rec->is_explicit ? " explicit" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
|||
}
|
||||
|
||||
bool
|
||||
skip_interface(struct lif_interface *iface, const char *ifname)
|
||||
skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state)
|
||||
{
|
||||
if (iface->is_template)
|
||||
{
|
||||
|
@ -123,16 +123,23 @@ skip_interface(struct lif_interface *iface, const char *ifname)
|
|||
if (up && iface->refcount > 0)
|
||||
{
|
||||
if (exec_opts.verbose)
|
||||
fprintf(stderr, "%s: skipping auto interface %s (already configured), use --force to force configuration\n",
|
||||
argv0, ifname);
|
||||
fprintf(stderr, "%s: skipping %sinterface %s (already configured), use --force to force configuration\n",
|
||||
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||
|
||||
if (update_state)
|
||||
{
|
||||
iface->is_explicit = true;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!up && iface->refcount == 0)
|
||||
{
|
||||
if (exec_opts.verbose)
|
||||
fprintf(stderr, "%s: skipping auto interface %s (already deconfigured), use --force to force deconfiguration\n",
|
||||
argv0, ifname);
|
||||
fprintf(stderr, "%s: skipping %sinterface %s (already deconfigured), use --force to force deconfiguration\n",
|
||||
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -140,7 +147,7 @@ skip_interface(struct lif_interface *iface, const char *ifname)
|
|||
}
|
||||
|
||||
bool
|
||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname)
|
||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state)
|
||||
{
|
||||
int lockfd = acquire_state_lock(exec_opts.state_file, ifname);
|
||||
|
||||
|
@ -150,7 +157,7 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
|||
return false;
|
||||
}
|
||||
|
||||
if (skip_interface(iface, ifname))
|
||||
if (skip_interface(iface, ifname, state, update_state))
|
||||
{
|
||||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
|
@ -178,6 +185,12 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
|||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
|
||||
if (up && update_state)
|
||||
{
|
||||
iface->is_explicit = true;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -202,7 +215,7 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
|
|||
fnmatch(opts->include_pattern, iface->ifname, 0))
|
||||
continue;
|
||||
|
||||
if (!change_interface(iface, collection, state, iface->ifname))
|
||||
if (!change_interface(iface, collection, state, iface->ifname, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -307,7 +320,7 @@ ifupdown_main(int argc, char *argv[])
|
|||
iface = entry->data;
|
||||
}
|
||||
|
||||
if (!change_interface(iface, &collection, &state, ifname))
|
||||
if (!change_interface(iface, &collection, &state, ifname, true))
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ applet_cmp(const void *a, const void *b)
|
|||
|
||||
void multicall_usage(int status) __attribute__((noreturn));
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -85,9 +87,11 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
self_applet = *app;
|
||||
|
||||
if (self_applet != &ifupdown_applet)
|
||||
process_options(*app, argc, argv);
|
||||
|
||||
return (*app)->main(argc, argv);
|
||||
return self_applet->main(argc, argv);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -99,8 +103,6 @@ multicall_main(int argc, char *argv[])
|
|||
return main(argc - 1, argv + 1);
|
||||
}
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
|
||||
void
|
||||
multicall_usage(int status)
|
||||
{
|
||||
|
|
|
@ -172,6 +172,9 @@ handle_auto(struct lif_interface_file_parse_state *state, char *token, char *buf
|
|||
if (!state->cur_iface->is_template)
|
||||
state->cur_iface->is_auto = true;
|
||||
|
||||
if (state->cur_iface->is_auto)
|
||||
state->cur_iface->is_explicit = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -253,6 +256,12 @@ handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bu
|
|||
return true;
|
||||
}
|
||||
|
||||
/* if we have a current interface, call lif_interface_finalize to finalize any
|
||||
* address properties by converting them to CIDR and flushing the netmask property.
|
||||
*/
|
||||
if (state->cur_iface != NULL)
|
||||
lif_interface_finalize(state->cur_iface);
|
||||
|
||||
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
|
@ -491,6 +500,11 @@ lif_interface_file_parse(struct lif_interface_file_parse_state *state, const cha
|
|||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* finalize any open interface */
|
||||
if (state->cur_iface != NULL)
|
||||
lif_interface_finalize(state->cur_iface);
|
||||
|
||||
state->cur_filename = old_filename;
|
||||
state->cur_lineno = old_lineno;
|
||||
return true;
|
||||
|
|
|
@ -84,6 +84,19 @@ count_set_bits(const char *netmask)
|
|||
return r;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
determine_interface_netmask(const struct lif_interface *iface, const struct lif_address *addr)
|
||||
{
|
||||
/* if netmask is not set, default to /24 or /64, ifupdown does so too */
|
||||
size_t netmask = addr->domain == AF_INET6 ? 64 : 24;
|
||||
|
||||
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
|
||||
if (entry != NULL)
|
||||
netmask = count_set_bits(entry->data);
|
||||
|
||||
return netmask;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen)
|
||||
{
|
||||
|
@ -91,14 +104,7 @@ lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry
|
|||
size_t orig_netmask = addr->netmask;
|
||||
|
||||
if (!addr->netmask)
|
||||
{
|
||||
/* if netmask is not set, default to 255.255.255.0, ifupdown does so too */
|
||||
addr->netmask = 24;
|
||||
|
||||
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
|
||||
if (entry != NULL)
|
||||
addr->netmask = count_set_bits(entry->data);
|
||||
}
|
||||
addr->netmask = determine_interface_netmask(iface, addr);
|
||||
|
||||
if (!lif_address_unparse(addr, buf, buflen, true))
|
||||
{
|
||||
|
@ -122,16 +128,6 @@ lif_interface_init(struct lif_interface *interface, const char *ifname)
|
|||
/* keep the 'vlan' executor as a config hint for backwards compatibility */
|
||||
if (strchr(ifname, '.') != NULL)
|
||||
lif_interface_use_executor(interface, "vlan");
|
||||
|
||||
if (!lif_config.use_hostname_for_dhcp)
|
||||
return;
|
||||
|
||||
/* learn a reasonable default hostname */
|
||||
struct utsname un;
|
||||
if (uname(&un) < 0)
|
||||
return;
|
||||
|
||||
lif_dict_add(&interface->vars, "hostname", strdup(un.nodename));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -211,6 +207,46 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor
|
|||
interface->is_bridge = true;
|
||||
else if (!strcmp(executor, "bond"))
|
||||
interface->is_bond = true;
|
||||
|
||||
if (strcmp(executor, "dhcp") || !lif_config.use_hostname_for_dhcp)
|
||||
return;
|
||||
|
||||
/* learn a reasonable default hostname */
|
||||
struct utsname un;
|
||||
if (uname(&un) < 0)
|
||||
return;
|
||||
|
||||
lif_dict_add(&interface->vars, "hostname", strdup(un.nodename));
|
||||
}
|
||||
|
||||
void
|
||||
lif_interface_finalize(struct lif_interface *interface)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
/* convert all addresses to CIDR notation. */
|
||||
LIF_DICT_FOREACH(iter, &interface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (strcmp(entry->key, "address"))
|
||||
continue;
|
||||
|
||||
struct lif_address *addr = entry->data;
|
||||
|
||||
if (!addr->netmask)
|
||||
addr->netmask = determine_interface_netmask(interface, addr);
|
||||
}
|
||||
|
||||
/* with all addresses converted to CIDR, netmask property is no longer needed. */
|
||||
struct lif_dict_entry *entry = lif_dict_find(&interface->vars, "netmask");
|
||||
|
||||
if (entry != NULL)
|
||||
{
|
||||
free(entry->data);
|
||||
|
||||
lif_dict_delete_entry(&interface->vars, entry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -223,6 +259,7 @@ lif_interface_collection_init(struct lif_dict *collection)
|
|||
/* always enable loopback interface as part of a collection */
|
||||
if_lo = lif_interface_collection_find(collection, "lo");
|
||||
if_lo->is_auto = true;
|
||||
if_lo->is_explicit = true;
|
||||
lif_interface_use_executor(if_lo, "loopback");
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ struct lif_interface {
|
|||
bool is_bond;
|
||||
bool is_template;
|
||||
bool is_pending;
|
||||
bool is_explicit;
|
||||
|
||||
bool has_config_error; /* error found in interface configuration */
|
||||
|
||||
|
@ -74,6 +75,7 @@ extern bool lif_interface_address_add(struct lif_interface *interface, const cha
|
|||
extern void lif_interface_address_delete(struct lif_interface *interface, const char *address);
|
||||
extern void lif_interface_fini(struct lif_interface *interface);
|
||||
extern void lif_interface_use_executor(struct lif_interface *interface, const char *executor);
|
||||
extern void lif_interface_finalize(struct lif_interface *interface);
|
||||
|
||||
extern void lif_interface_collection_init(struct lif_dict *collection);
|
||||
extern void lif_interface_collection_fini(struct lif_dict *collection);
|
||||
|
|
|
@ -396,6 +396,15 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!up && iface->is_explicit)
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- interface is marked as explicitly configured\n",
|
||||
iface->ifname, parent->ifname);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: changing state of dependent interface %s (of %s) to %s\n",
|
||||
iface->ifname, parent->ifname, up ? "up" : "down");
|
||||
|
|
|
@ -29,8 +29,13 @@ lif_state_read(struct lif_dict *state, FILE *fd)
|
|||
char *bufp = linebuf;
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
char *refcount = lif_next_token(&bufp);
|
||||
char *explicit = lif_next_token(&bufp);
|
||||
size_t rc = 1;
|
||||
char *equals_p = strchr(linebuf, '=');
|
||||
bool is_explicit = false;
|
||||
|
||||
if (*explicit && !strcmp(explicit, "explicit"))
|
||||
is_explicit = true;
|
||||
|
||||
if (*refcount)
|
||||
{
|
||||
|
@ -42,12 +47,12 @@ lif_state_read(struct lif_dict *state, FILE *fd)
|
|||
|
||||
if (equals_p == NULL)
|
||||
{
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc, .is_explicit = is_explicit });
|
||||
continue;
|
||||
}
|
||||
|
||||
*equals_p++ = '\0';
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc, .is_explicit = is_explicit });
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -99,6 +104,7 @@ lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interfac
|
|||
|
||||
rec->mapped_if = strdup(iface->ifname);
|
||||
rec->refcount = iface->refcount;
|
||||
rec->is_explicit = iface->is_explicit;
|
||||
|
||||
lif_dict_add(state, ifname, rec);
|
||||
}
|
||||
|
@ -128,7 +134,8 @@ lif_state_write(const struct lif_dict *state, FILE *f)
|
|||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_state_record *rec = entry->data;
|
||||
|
||||
fprintf(f, "%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
||||
fprintf(f, "%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||
rec->is_explicit ? " explicit" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +182,7 @@ lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection)
|
|||
struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if);
|
||||
|
||||
iface->refcount = rec->refcount;
|
||||
iface->is_explicit = rec->is_explicit;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -17,11 +17,14 @@
|
|||
#define LIBIFUPDOWN_STATE_H__GUARD
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "libifupdown/interface.h"
|
||||
|
||||
struct lif_state_record {
|
||||
char *mapped_if;
|
||||
size_t refcount;
|
||||
|
||||
bool is_explicit;
|
||||
};
|
||||
|
||||
extern bool lif_state_read(struct lif_dict *state, FILE *f);
|
||||
|
|
|
@ -2,6 +2,7 @@ syntax(2)
|
|||
|
||||
test_suite('ifupdown-ng')
|
||||
|
||||
atf_test_program{name='multicall_test'}
|
||||
atf_test_program{name='ifquery_test'}
|
||||
atf_test_program{name='ifup_test'}
|
||||
atf_test_program{name='ifdown_test'}
|
||||
|
|
14
tests/fixtures/stanza-merging.interfaces
vendored
Normal file
14
tests/fixtures/stanza-merging.interfaces
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
# cidr and without-cidr should be equivalent
|
||||
iface cidr
|
||||
address 203.0.113.1/32
|
||||
|
||||
iface cidr
|
||||
address 203.0.113.2/24
|
||||
|
||||
iface without-cidr
|
||||
address 203.0.113.1
|
||||
netmask 32
|
||||
|
||||
iface without-cidr
|
||||
address 203.0.113.2
|
||||
netmask 24
|
5
tests/fixtures/without-netmask.interfaces
vendored
Normal file
5
tests/fixtures/without-netmask.interfaces
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
iface v6
|
||||
address 2001:470:1f10::1
|
||||
|
||||
iface v4
|
||||
address 203.0.113.2
|
|
@ -34,7 +34,11 @@ tests_init \
|
|||
vlan_explicit_learned_dependency \
|
||||
vlan_guessed_learned_dependency \
|
||||
vlan_complex_learned_dependency \
|
||||
wireguard
|
||||
wireguard \
|
||||
default_netmask_v4 \
|
||||
default_netmask_v6 \
|
||||
stanza_merging_with_cidr \
|
||||
stanza_merging_without_cidr
|
||||
|
||||
noargs_body() {
|
||||
atf_check -s exit:1 -e ignore ifquery -S/dev/null
|
||||
|
@ -226,3 +230,29 @@ wireguard_body() {
|
|||
-o match:"use wireguard" \
|
||||
ifquery -E $EXECUTORS_LINUX -i $FIXTURES/wireguard.interfaces wg0
|
||||
}
|
||||
|
||||
default_netmask_v4_body() {
|
||||
atf_check -s exit:0 \
|
||||
-o match:"203.0.113.2/24" \
|
||||
ifquery -i $FIXTURES/without-netmask.interfaces -p address v4
|
||||
}
|
||||
|
||||
default_netmask_v6_body() {
|
||||
atf_check -s exit:0 \
|
||||
-o match:"2001:470:1f10::1/64" \
|
||||
ifquery -i $FIXTURES/without-netmask.interfaces -p address v6
|
||||
}
|
||||
|
||||
stanza_merging_with_cidr_body() {
|
||||
atf_check -s exit:0 \
|
||||
-o match:"203.0.113.1/32" \
|
||||
-o match:"203.0.113.2/24" \
|
||||
ifquery -i $FIXTURES/stanza-merging.interfaces -p address cidr
|
||||
}
|
||||
|
||||
stanza_merging_without_cidr_body() {
|
||||
atf_check -s exit:0 \
|
||||
-o match:"203.0.113.1/32" \
|
||||
-o match:"203.0.113.2/24" \
|
||||
ifquery -i $FIXTURES/stanza-merging.interfaces -p address without-cidr
|
||||
}
|
||||
|
|
11
tests/multicall_test
Executable file
11
tests/multicall_test
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env atf-sh
|
||||
|
||||
. $(atf_get_srcdir)/test_env.sh
|
||||
|
||||
tests_init \
|
||||
regress_getopt
|
||||
|
||||
regress_getopt_body() {
|
||||
atf_check -e not-inline:'-F: applet not found' -o ignore -s exit:1 \
|
||||
ifupdown ifquery -F
|
||||
}
|
Loading…
Reference in a new issue