diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index d5c9fa5..3d217a9 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -263,6 +263,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) { @@ -501,6 +507,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; diff --git a/libifupdown/interface.c b/libifupdown/interface.c index b18e318..0294383 100644 --- a/libifupdown/interface.c +++ b/libifupdown/interface.c @@ -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 = addr->domain == AF_INET6 ? 64 : 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)) { @@ -213,6 +219,36 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor 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 lif_interface_collection_init(struct lif_dict *collection) { diff --git a/libifupdown/interface.h b/libifupdown/interface.h index 0c6d8b2..49c867d 100644 --- a/libifupdown/interface.h +++ b/libifupdown/interface.h @@ -75,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); diff --git a/tests/fixtures/stanza-merging.interfaces b/tests/fixtures/stanza-merging.interfaces new file mode 100644 index 0000000..6327cbc --- /dev/null +++ b/tests/fixtures/stanza-merging.interfaces @@ -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 diff --git a/tests/ifquery_test b/tests/ifquery_test index 8aded63..3fac522 100755 --- a/tests/ifquery_test +++ b/tests/ifquery_test @@ -38,7 +38,9 @@ tests_init \ allow_undefined_positive \ allow_undefined_negative \ default_netmask_v4 \ - default_netmask_v6 + default_netmask_v6 \ + stanza_merging_with_cidr \ + stanza_merging_without_cidr noargs_body() { atf_check -s exit:1 -e ignore ifquery -S/dev/null @@ -256,3 +258,17 @@ default_netmask_v6_body() { -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 +}