confd: add support for IPv4LL request-address option

This patch allows a user to specify a specific 169.254/16 address that
the zeroconf client starts with when probing for a free address.  If the
probe fails it falls back to its default algorithm.

Fixes #628

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2024-09-26 15:49:45 +02:00
parent 151119ef0e
commit add52cdb38
6 changed files with 157 additions and 94 deletions
+7
View File
@@ -598,6 +598,13 @@ As shown, the link-local IPv4 address is configured with `set autconf
enabled true`. The resulting address (169.254.1.3/16) is of type
*random* ([ietf-ip.yang][2]).
The IPv4LL client also supports a `request-address` setting which can be
used to "seed" the client's starting address. If the address is free it
will be used, otherwise it falls back to the default algorithm.
admin@example:/config/interface/eth0/ipv4/> set autoconf request-address 169.254.1.2
#### Use of DHCP for IPv4 address assignment
![Using DHCP for IPv4 address assignment](img/ip-address-example-ipv4-dhcp.svg)
@@ -45,8 +45,10 @@ endif
ifeq ($(BR2_PACKAGE_AVAHI_AUTOIPD),y)
define SKELETON_INIT_FINIT_SET_AVAHI_AUTOIPD
echo "service [2345789] name:zeroconf :%i avahi-autoipd --force-bind --syslog %i -- ZeroConf for %i" \
> $(FINIT_D)/available/zeroconf@.conf
echo 'service name:zeroconf :%i env:-/etc/default/zeroconf-%i \' >$(FINIT_D)/available/zeroconf@.conf
echo ' <!> kill:5 pid:!/run/avahi-autoipd.%i.pid \'>>$(FINIT_D)/available/zeroconf@.conf
echo ' [2345789] log avahi-autoipd $$ZEROCONF_ARGS %i \'>>$(FINIT_D)/available/zeroconf@.conf
echo ' -- ZeroConf for %i' >>$(FINIT_D)/available/zeroconf@.conf
endef
SKELETON_INIT_FINIT_POST_INSTALL_TARGET_HOOKS += SKELETON_INIT_FINIT_SET_AVAHI_AUTOIPD
endif
+66 -23
View File
@@ -537,45 +537,89 @@ static int netdag_gen_ipv6_autoconf(struct dagger *net, struct lyd_node *cif,
return 0;
}
/*
* Check if ipv4 is enabled, only then can autoconf be enabled, in all
* other cases it must be disabled. Since we have multiple settings in
* autoconf, we check if either is modified (diff), in which case we not
* only enable, but also "touch" the Finit service for avahi-autoipd to
* ensure it is (re)started.
*
* Note: in Infix, regardless of the IPv4 configuration, any link-local
* link-local address is disabled when the interface is being used
* as a bridge port.
*
* Also, IPv4LL is not defined for loopback, so always skip there.
*/
static int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif,
struct lyd_node *dif)
{
struct lyd_node *ipconf = lydx_get_child(cif, "ipv4");
struct lyd_node *ipdiff = lydx_get_child(dif, "ipv4");
const char *ifname = lydx_get_cattr(dif, "name");
struct lyd_node *node, *zcip;
struct lydx_diff nd;
struct lyd_node *zcip;
char defaults[64];
FILE *initctl;
int err = 0;
if (!strcmp(ifname, "lo"))
return 0;
/* client defults for this interface, needed in both cases */
snprintf(defaults, sizeof(defaults), "/etc/default/zeroconf-%s", ifname);
/* no ipv4 at all, ipv4 selectively disabled, or interface is a bridge port */
if (!ipconf || !lydx_is_enabled(ipconf, "enabled") || is_bridge_port(cif))
goto disable;
if (lydx_get_op(lydx_get_child(ipdiff, "enabled")) == LYDX_OP_REPLACE) {
node = lydx_get_child(ipconf, "autoconf");
if (node && lydx_is_enabled(node, "enabled"))
goto enable;
goto disable;
}
/*
* when enabled, we may have been enabled before, but skipped
* for various reasons: was bridge port, ipv4 was disabled...
*/
zcip = lydx_get_child(ipconf, "autoconf");
if (zcip && lydx_is_enabled(zcip, "enabled")) {
struct lyd_node *node;
const char *addr;
int diff = 0;
FILE *fp;
zcip = lydx_get_child(ipdiff, "autoconf");
if (!zcip || !(node = lydx_get_child(zcip, "enabled")))
return 0;
/* check for any changes in this container */
node = lydx_get_child(ipdiff, "autoconf");
if (node) {
const struct lyd_node *tmp;
lydx_get_diff(node, &nd);
if (nd.new && !strcmp(nd.val, "true")) {
enable:
initctl = dagger_fopen_next(net, "init", ifname,
60, "zeroconf-up.sh");
tmp = lydx_get_child(node, "enabled");
if (tmp)
diff++;
tmp = lydx_get_child(node, "request-address");
if (tmp)
diff++;
}
fp = fopen(defaults, "w");
if (!fp) {
ERRNO("Failed creating %s, cannot enable IPv4LL on %s", defaults, ifname);
return -EIO;
}
fprintf(fp, "ZEROCONF_ARGS=\"--force-bind --syslog ");
addr = lydx_get_cattr(zcip, "request-address");
if (addr)
fprintf(fp, "--start=%s", addr);
fprintf(fp, "\"\n");
fclose(fp);
initctl = dagger_fopen_next(net, "init", ifname, 60, "zeroconf-up.sh");
if (!initctl)
return -EIO;
fprintf(initctl,
"initctl -bnq enable zeroconf@%s.conf\n", ifname);
/* on enable, or reactivation, it is enough to ensure the service is enabled */
fprintf(initctl, "initctl -bnq enable zeroconf@%s.conf\n", ifname);
/* on changes to autoconf we must ensure Finit restarts the service */
if (diff)
fprintf(initctl, "initctl -bnq touch zeroconf@%s.conf\n", ifname);
} else {
disable:
initctl = dagger_fopen_current(net, "exit", ifname,
40, "zeroconf-down.sh");
initctl = dagger_fopen_current(net, "exit", ifname, 40, "zeroconf-down.sh");
if (!initctl) {
/* check if in bootstrap (pre gen 0) */
if (errno == EUNATCH)
@@ -583,9 +627,8 @@ static int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif,
return -EIO;
}
fprintf(initctl,
"initctl -bnq disable zeroconf@%s.conf\n", ifname);
fprintf(initctl, "initctl -bnq disable zeroconf@%s.conf\n", ifname);
fprintf(initctl, "rm -f %s\n", defaults);
err = netdag_exit_reload(net);
}
+1 -1
View File
@@ -25,7 +25,7 @@ MODULES=(
"ietf-hardware@2018-03-13.yang -e hardware-state"
"infix-hardware@2024-04-25.yang"
"ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2023-09-14.yang"
"infix-ip@2024-09-16.yang"
"infix-if-type@2024-01-29.yang"
"infix-routing@2024-09-20.yang"
"ieee802-dot1ab-lldp@2022-03-15.yang"
-68
View File
@@ -1,68 +0,0 @@
module infix-ip {
yang-version 1.1;
namespace "urn:infix:params:xml:ns:yang:infix-ip";
prefix infix-ip;
import ietf-interfaces {
prefix if;
}
import ietf-ip {
prefix ip;
}
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
description
"This module augments ietf-ip with an IPv4 link-local autoconf";
revision 2023-09-14 {
description
"Added deviations for unsupported parts of ietf-ip.";
}
revision 2023-04-24 {
description
"Initial revision.";
reference
"RFC 7277: A YANG Data Model for IP Management";
}
/*
* Data nodes
*/
augment "/if:interfaces/if:interface/ip:ipv4" {
container autoconf {
description
"Parameters to control the autoconfiguration of IPv4 address.";
leaf enabled {
type boolean;
default false;
description
"Use a ZeroConf/IPv4LL agent to retrieve an 169.254/16 address.";
reference
"RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses";
}
}
}
deviation "/if:interfaces/if:interface/ip:ipv4/ip:address/ip:subnet/ip:netmask" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv4/ip:neighbor" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv6/ip:address/ip:status" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv6/ip:neighbor" {
deviate not-supported;
}
}
+79
View File
@@ -0,0 +1,79 @@
module infix-ip {
yang-version 1.1;
namespace "urn:infix:params:xml:ns:yang:infix-ip";
prefix infix-ip;
import ietf-interfaces {
prefix if;
}
import ietf-ip {
prefix ip;
}
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
description "This module augments ietf-ip with Infix extensions and deviations.";
revision 2024-09-16 {
description "Add support for IPv4LL request-address.";
reference "Internal.";
}
revision 2023-09-14 {
description "Added deviations for unsupported parts of ietf-ip.";
reference "Internal.";
}
revision 2023-04-24 {
description "Initial revision.";
reference "RFC 7277: A YANG Data Model for IP Management";
}
/*
* Data nodes
*/
augment "/if:interfaces/if:interface/ip:ipv4" {
container autoconf {
description "Parameters to control the autoconfiguration of IPv4 address.";
reference "RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses";
leaf enabled {
description "Use a ZeroConf/IPv4LL agent to retrieve an 169.254/16 address.";
type boolean;
}
leaf request-address {
description "Try to acquire the specified IP address, if available.
With this setting the IPv4LL client will start by
requesting this address. However, if it is not
available it falls back to the default algorithm.";
type inet:ipv4-address;
must "substring(., 1, 7) = '169.254'" {
error-message "Must be from the IPv4LL range 169.254.0.0/16.";
}
must "not(substring(., string-length(.) - 1, 2) = '.0' or substring(., string-length(.) - 3, 4) = '.255')" {
error-message "Addresses ending in .0 or .255 are reserved.";
}
}
}
}
deviation "/if:interfaces/if:interface/ip:ipv4/ip:address/ip:subnet/ip:netmask" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv4/ip:neighbor" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv6/ip:address/ip:status" {
deviate not-supported;
}
deviation "/if:interfaces/if:interface/ip:ipv6/ip:neighbor" {
deviate not-supported;
}
}