Merge pull request #1223 from kernelkit/migrate-dhcp-client

Relocate /dhcp-client to /interfaces/interface/ipv4/dhcp
This commit is contained in:
Joachim Wiberg
2025-11-06 20:03:12 +01:00
committed by GitHub
32 changed files with 412 additions and 331 deletions
@@ -99,7 +99,20 @@
{ {
"name": "wan", "name": "wan",
"type": "infix-if-type:ethernet", "type": "infix-if-type:ethernet",
"ietf-ip:ipv6": {} "ietf-ip:ipv6": {},
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{"id": "ntp-server"},
{"id": "broadcast"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "router"},
{"id": "netmask"}
]
}
}
}, },
{ {
"name": "wifi0", "name": "wifi0",
@@ -221,36 +234,6 @@
}, },
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo=" "infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo="
}, },
"infix-dhcp-client:dhcp-client": {
"client-if": [
{
"if-name": "wan",
"option": [
{
"id": "ntp-server"
},
{
"id": "broadcast"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "router"
},
{
"id": "netmask"
}
]
}
]
},
"infix-dhcp-server:dhcp-server": { "infix-dhcp-server:dhcp-server": {
"option": [ "option": [
{ {
@@ -311,7 +294,7 @@
] ]
}, },
"infix-meta:meta": { "infix-meta:meta": {
"version": "1.5" "version": "1.6"
}, },
"infix-services:mdns": { "infix-services:mdns": {
"enabled": true "enabled": true
@@ -58,7 +58,20 @@
{ {
"name": "wan", "name": "wan",
"type": "infix-if-type:ethernet", "type": "infix-if-type:ethernet",
"ietf-ip:ipv6": {} "ietf-ip:ipv6": {},
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{"id": "ntp-server"},
{"id": "broadcast"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "router"},
{"id": "netmask"}
]
}
}
} }
] ]
}, },
@@ -172,36 +185,6 @@
}, },
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo=" "infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo="
}, },
"infix-dhcp-client:dhcp-client": {
"client-if": [
{
"if-name": "wan",
"option": [
{
"id": "ntp-server"
},
{
"id": "broadcast"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "router"
},
{
"id": "netmask"
}
]
}
]
},
"infix-dhcp-server:dhcp-server": { "infix-dhcp-server:dhcp-server": {
"option": [ "option": [
{ {
@@ -262,7 +245,7 @@
] ]
}, },
"infix-meta:meta": { "infix-meta:meta": {
"version": "1.5" "version": "1.6"
}, },
"infix-services:mdns": { "infix-services:mdns": {
"enabled": true "enabled": true
@@ -37,7 +37,20 @@
}, },
{ {
"name": "eth0", "name": "eth0",
"type": "infix-if-type:ethernet" "type": "infix-if-type:ethernet",
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{"id": "netmask"},
{"id": "broadcast"},
{"id": "router"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "ntp-server"}
]
}
}
}, },
{ {
"name": "wifi0", "name": "wifi0",
@@ -157,38 +170,8 @@
}, },
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo=" "infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo="
}, },
"infix-dhcp-client:dhcp-client": {
"client-if": [
{
"if-name": "eth0",
"option": [
{
"id": "netmask"
},
{
"id": "broadcast"
},
{
"id": "router"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "ntp-server"
}
]
}
]
},
"infix-meta:meta": { "infix-meta:meta": {
"version": "1.5" "version": "1.6"
}, },
"infix-services:mdns": { "infix-services:mdns": {
"enabled": true "enabled": true
+6
View File
@@ -9,6 +9,12 @@ All notable changes to the project are documented in this file.
### Changes ### Changes
- Upgrade Linux kernel to 6.12.57 (LTS) - Upgrade Linux kernel to 6.12.57 (LTS)
- The DHCP client configuration has moved from `/infix-dhcp-client:dhcp-client`
to `/interfaces/interface[name]/ipv4/infix-dhcp-client:dhcp`, issue #1109.
The configuration is automatically migrated on upgrade. The DHCP client is
now enabled using a presence container instead of a separate `enabled` leaf
- The `enabled` nore for IPv4 autoconf (ZeroConf) has been dropped, `autoconf`
is now a presence container. Configuration automatically migrated on upgrade
- Improvements to `sdcard.img` generation, useful for developers mostly: - Improvements to `sdcard.img` generation, useful for developers mostly:
- The NanoPi R2S bootloader is now automatically built and uploaded to - The NanoPi R2S bootloader is now automatically built and uploaded to
the [`latest-boot` release][lastest-boot] tag the [`latest-boot` release][lastest-boot] tag
+37 -11
View File
@@ -996,7 +996,7 @@ default.
admin@example:/> configure admin@example:/> configure
admin@example:/config/> edit interface eth0 ipv4 admin@example:/config/> edit interface eth0 ipv4
admin@example:/config/interface/eth0/ipv4/> set address 10.0.1.1 prefix-length 24 admin@example:/config/interface/eth0/ipv4/> set address 10.0.1.1 prefix-length 24
admin@example:/config/interface/eth0/ipv4/> set autoconf enabled true admin@example:/config/interface/eth0/ipv4/> set autoconf
admin@example:/config/interface/eth0/ipv4/> diff admin@example:/config/interface/eth0/ipv4/> diff
+interfaces { +interfaces {
+ interface eth0 { + interface eth0 {
@@ -1004,9 +1004,7 @@ default.
+ address 10.0.1.1 { + address 10.0.1.1 {
+ prefix-length 24; + prefix-length 24;
+ } + }
+ autoconf { + autoconf;
+ enabled true;
+ }
+ } + }
+ } + }
+} +}
@@ -1022,15 +1020,18 @@ default.
ipv6 ::1/128 (static) ipv6 ::1/128 (static)
admin@example:/> admin@example:/>
As shown, the link-local IPv4 address is configured with `set autconf As shown, the link-local IPv4 address is configured with `set autoconf`.
enabled true`. The resulting address (169.254.1.3/16) is of type The presence of the `autoconf` container enables IPv4 link-local address
*random* ([ietf-ip.yang][2]). assignment. 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 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 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. 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 admin@example:/config/interface/eth0/ipv4/> edit autoconf
admin@example:/config/interface/eth0/ipv4/autoconf/> set request-address 169.254.1.2
admin@example:/config/interface/eth0/ipv4/autoconf/> leave
#### Use of DHCP for IPv4 address assignment #### Use of DHCP for IPv4 address assignment
@@ -1038,9 +1039,9 @@ will be used, otherwise it falls back to the default algorithm.
![Using DHCP for IPv4 address assignment](img/ip-address-example-ipv4-dhcp.svg) ![Using DHCP for IPv4 address assignment](img/ip-address-example-ipv4-dhcp.svg)
admin@example:/> configure admin@example:/> configure
admin@example:/config/> edit dhcp-client admin@example:/config/> edit interface eth0 ipv4
admin@example:/config/dhcp-client/> set client-if eth0 admin@example:/config/interface/eth0/ipv4/> set dhcp
admin@example:/config/dhcp-client/> leave admin@example:/config/interface/eth0/ipv4/> leave
admin@example:/> show interfaces admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA INTERFACE PROTOCOL STATE DATA
eth0 ethernet UP 02:00:00:00:00:00 eth0 ethernet UP 02:00:00:00:00:00
@@ -1053,6 +1054,31 @@ will be used, otherwise it falls back to the default algorithm.
The resulting address (10.1.2.100/24) is of type *dhcp*. The resulting address (10.1.2.100/24) is of type *dhcp*.
To configure DHCP client options, such as sending a specific hostname to the
server, you can specify options with values:
```
admin@example:/> configure
admin@example:/config/> edit interface eth0 ipv4 dhcp
admin@example:/config/interface/eth0/ipv4/dhcp/> set option hostname value myhost
admin@example:/config/interface/eth0/ipv4/dhcp/> show
option hostname {
value myhost;
}
admin@example:/config/interface/eth0/ipv4/dhcp/> leave
admin@example:/>
```
> [!TIP]
> The special value `auto` can be used with the hostname option to
> automatically use the configured system hostname.
Other useful DHCP options include:
- `client-id` - Send a specific client identifier to the server
- `route-preference` - Set the administrative distance for DHCP-learned routes (default: 5)
For advanced usage with vendor-specific options, see the YANG model.
#### Disabling IPv6 link-local address(es) #### Disabling IPv6 link-local address(es)
+16 -28
View File
@@ -173,11 +173,13 @@ Enabling DHCPv4 client on interface *e0*, with current default options.
``` ```
~$ cat /tmp/file.json ~$ cat /tmp/file.json
{ {
"infix-dhcp-client:dhcp-client": { "ietf-interfaces:interfaces": {
"enabled": true, "interface": [
"client-if": [
{ {
"if-name": "e0" "name": "e0",
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {}
}
} }
] ]
} }
@@ -187,13 +189,18 @@ Enabling DHCPv4 client on interface *e0*, with current default options.
~$ ~$
``` ```
Disabling DHCPv4 client. Disabling DHCPv4 client on interface *e0* (remove the dhcp container).
``` ```
~$ cat /tmp/file.json ~$ cat /tmp/file.json
{ {
"infix-dhcp-client:dhcp-client": { "ietf-interfaces:interfaces": {
"enabled": false "interface": [
{
"name": "e0",
"ietf-ip:ipv4": {}
}
]
} }
} }
~$ scp file.json admin@example.local:/tmp/file.json ~$ scp file.json admin@example.local:/tmp/file.json
@@ -201,27 +208,8 @@ Disabling DHCPv4 client.
~$ ~$
``` ```
Configuration for client interface *e0* remains, but does not apply as To fully remove the DHCPv4 client configuration, remove the `infix-dhcp-client:dhcp`
DHCPv4 is disabled. container from the interface's ipv4 configuration.
```
admin@example:~$ sysrepocfg -X -fjson -d running -x "/infix-dhcp-client:dhcp-client"
{
"infix-dhcp-client:dhcp-client": {
"enabled": false,
"client-if": [
{
"if-name": "e0"
}
]
}
}
admin@example:~$
```
To fully remove the DHCPv4 client configuration or a specific
*client-if* with sysrepocfg, one would need to read out the full
configuration, remove relevant parts and read back.
## Enable/Disable IPv6 ## Enable/Disable IPv6
+1 -1
View File
@@ -4,7 +4,7 @@
# #
################################################################################ ################################################################################
CONFD_VERSION = 1.5 CONFD_VERSION = 1.6
CONFD_SITE_METHOD = local CONFD_SITE_METHOD = local
CONFD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/confd CONFD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/confd
CONFD_LICENSE = BSD-3-Clause CONFD_LICENSE = BSD-3-Clause
+17 -15
View File
@@ -169,9 +169,23 @@ if [ -n "$bridge" ]; then
"name": "$bridge", "name": "$bridge",
"type": "infix-if-type:bridge", "type": "infix-if-type:bridge",
"ietf-ip:ipv4": { "ietf-ip:ipv4": {
"infix-ip:autoconf": { EOF
"enabled": $ipv4 if [ "$ipv4" = "true" ]; then
} cat <<EOF
"infix-ip:autoconf": {}
EOF
if [ "$dhcp" = "true" ]; then
cat <<EOF
,
"infix-dhcp-client:dhcp": {}
EOF
fi
elif [ "$dhcp" = "true" ]; then
cat <<EOF
"infix-dhcp-client:dhcp": {}
EOF
fi
cat <<EOF
}, },
"ietf-ip:ipv6": { "ietf-ip:ipv6": {
"enabled": true, "enabled": true,
@@ -195,18 +209,6 @@ $(for iface in $ifaces; do gen_iface_json "$iface"; done)
$(for iface in $ports; do gen_iface_json "$iface" "$bridge"; done) $(for iface in $ports; do gen_iface_json "$iface" "$bridge"; done)
] ]
EOF EOF
if [ "$dhcp" = "true" ] && [ -n "$bridge" ]; then
cat <<EOF
},
"infix-dhcp-client:dhcp-client": {
"enabled": true,
"client-if": [
{
"if-name": "$bridge"
}
]
EOF
fi
cat <<EOF cat <<EOF
} }
} }
+2 -1
View File
@@ -1,6 +1,6 @@
AC_PREREQ(2.61) AC_PREREQ(2.61)
# confd version is same as system YANG model version, step on breaking changes # confd version is same as system YANG model version, step on breaking changes
AC_INIT([confd], [1.5], [https://github.com/kernelkit/infix/issues]) AC_INIT([confd], [1.6], [https://github.com/kernelkit/infix/issues])
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects) AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
AM_SILENT_RULES(yes) AM_SILENT_RULES(yes)
@@ -19,6 +19,7 @@ AC_CONFIG_FILES([
share/migrate/1.3/Makefile share/migrate/1.3/Makefile
share/migrate/1.4/Makefile share/migrate/1.4/Makefile
share/migrate/1.5/Makefile share/migrate/1.5/Makefile
share/migrate/1.6/Makefile
yang/Makefile yang/Makefile
yang/confd/Makefile yang/confd/Makefile
yang/test-mode/Makefile yang/test-mode/Makefile
+54
View File
@@ -0,0 +1,54 @@
#!/bin/sh
# Migrate DHCP client configuration from standalone model to ietf-ip augment
# From: /infix-dhcp-client:dhcp-client/client-if[if-name]
# To: /ietf-interfaces:interfaces/interface[name]/ipv4/infix-dhcp-client:dhcp
# Note: Drops configurations where enabled == false, since presence = enabled
file=$1
temp=${file}.tmp
jq '
if .["infix-dhcp-client:dhcp-client"] then
# 1. Check global enabled flag
if .["infix-dhcp-client:dhcp-client"].enabled == false then
# Global dhcp-client disabled, drop entire configuration
del(.["infix-dhcp-client:dhcp-client"])
else
# Global enabled (true or absent), process client-if entries
.["infix-dhcp-client:dhcp-client"]."client-if" as $clients |
# 2. Create a dictionary (map) of DHCP configs keyed by interface name
($clients // [] | map(
# Only keep entries where enabled is TRUE or ABSENT
select(.enabled == false | not) |
{
key: ."if-name",
value: {
# Construct the new presence container, stripping old keys
"infix-dhcp-client:dhcp": (
. | del(."if-name", .enabled)
)
}
}
) | from_entries) as $dhcp_configs |
# 3. Merge/Integrate DHCP config data into existing interfaces
# Use "?" for optional chaining on "interfaces"
.["ietf-interfaces:interfaces"]?.interface |= map(
if $dhcp_configs[.name] then
# Merge the new config into ipv4. Use // {} to ensure ipv4 exists if missing.
.["ietf-ip:ipv4"] = (.["ietf-ip:ipv4"] // {}) + $dhcp_configs[.name]
else
.
end
) |
# 4. Cleanup the old container
del(.["infix-dhcp-client:dhcp-client"])
end
else
# If no old DHCP config existed, return the input unchanged
.
end
' "$file" > "$temp" && mv "$temp" "$file"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
# Migrate IPv4 autoconf from enabled leaf to presence container
# Remove the "enabled" leaf, keeping the container only if it was enabled
file=$1
temp=${file}.tmp
jq '
if .["ietf-interfaces:interfaces"] then
.["ietf-interfaces:interfaces"].interface |= map(
if .["ietf-ip:ipv4"]?."infix-ip:autoconf" then
if .["ietf-ip:ipv4"]."infix-ip:autoconf".enabled == false then
# Remove autoconf container if it was disabled
.["ietf-ip:ipv4"] |= del(."infix-ip:autoconf")
else
# Keep autoconf but remove the enabled leaf
.["ietf-ip:ipv4"]."infix-ip:autoconf" |= del(.enabled)
end
else
.
end
)
else
.
end
' "$file" > "$temp" && mv "$temp" "$file"
+3
View File
@@ -0,0 +1,3 @@
migratedir = $(pkgdatadir)/migrate/1.6
dist_migrate_DATA = 10-dhcp-client-to-ipv4.sh \
20-autoconf-to-presence.sh
+1 -1
View File
@@ -1,2 +1,2 @@
SUBDIRS = 1.0 1.1 1.2 1.3 1.4 1.5 SUBDIRS = 1.0 1.1 1.2 1.3 1.4 1.5 1.6
migratedir = $(pkgdatadir)/migrate migratedir = $(pkgdatadir)/migrate
+13 -1
View File
@@ -158,7 +158,7 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
last_request = request_id; last_request = request_id;
last_event = event; last_event = event;
if (event == SR_EV_CHANGE || event == SR_EV_DONE) { if (event == SR_EV_UPDATE || event == SR_EV_CHANGE || event == SR_EV_DONE) {
rc = srx_get_diff(session, &diff); rc = srx_get_diff(session, &diff);
if (rc != SR_ERR_OK) { if (rc != SR_ERR_OK) {
ERROR("Failed to get diff: %d", rc); ERROR("Failed to get diff: %d", rc);
@@ -215,8 +215,10 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
goto free_diff; goto free_diff;
/* infix-containers */ /* infix-containers */
#ifdef CONTAINERS
if ((rc = infix_containers_change(session, config, diff, event, confd))) if ((rc = infix_containers_change(session, config, diff, event, confd)))
goto free_diff; goto free_diff;
#endif
/* ietf-hardware */ /* ietf-hardware */
if ((rc = ietf_hardware_change(session, config, diff, event, confd))) if ((rc = ietf_hardware_change(session, config, diff, event, confd)))
@@ -234,6 +236,10 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
if ((rc = infix_firewall_change(session, config, diff, event, confd))) if ((rc = infix_firewall_change(session, config, diff, event, confd)))
goto free_diff; goto free_diff;
/* infix-meta */
if ((rc = infix_meta_change_cb(session, config, diff, event, confd)))
goto free_diff;
if (cfg) if (cfg)
sr_release_data(cfg); sr_release_data(cfg);
@@ -383,9 +389,11 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
rc = ietf_system_rpc_init(&confd); rc = ietf_system_rpc_init(&confd);
if (rc) if (rc)
goto err; goto err;
#ifdef CONTAINERS
rc = infix_containers_rpc_init(&confd); rc = infix_containers_rpc_init(&confd);
if (rc) if (rc)
goto err; goto err;
#endif
rc = infix_dhcp_server_rpc_init(&confd); rc = infix_dhcp_server_rpc_init(&confd);
if (rc) if (rc)
goto err; goto err;
@@ -407,6 +415,10 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
goto err; goto err;
/* Candidate infer configurations */ /* Candidate infer configurations */
rc = ietf_interfaces_cand_init(&confd);
if (rc)
goto err;
rc = ietf_hardware_candidate_init(&confd); rc = ietf_hardware_candidate_init(&confd);
if (rc) if (rc)
goto err; goto err;
+1 -1
View File
@@ -226,7 +226,7 @@ int infix_factory_rpc_init(struct confd *confd);
int ietf_factory_default_rpc_init(struct confd *confd); int ietf_factory_default_rpc_init(struct confd *confd);
/* infix-meta.c */ /* infix-meta.c */
int infix_meta_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd); int infix_meta_change_cb(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* infix-system-software.c */ /* infix-system-software.c */
int infix_system_sw_rpc_init(struct confd *confd); int infix_system_sw_rpc_init(struct confd *confd);
+3 -4
View File
@@ -94,7 +94,7 @@ int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif,
* for various reasons: was bridge port, ipv4 was disabled... * for various reasons: was bridge port, ipv4 was disabled...
*/ */
zcip = lydx_get_child(ipconf, "autoconf"); zcip = lydx_get_child(ipconf, "autoconf");
if (zcip && lydx_is_enabled(zcip, "enabled")) { if (zcip) {
struct lyd_node *node; struct lyd_node *node;
const char *addr; const char *addr;
int diff = 0; int diff = 0;
@@ -105,9 +105,8 @@ int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif,
if (node) { if (node) {
const struct lyd_node *tmp; const struct lyd_node *tmp;
tmp = lydx_get_child(node, "enabled"); /* presence container created or deleted */
if (tmp) diff++;
diff++;
tmp = lydx_get_child(node, "request-address"); tmp = lydx_get_child(node, "request-address");
if (tmp) if (tmp)
diff++; diff++;
+1
View File
@@ -356,6 +356,7 @@ int infix_containers_change(sr_session_ctx_t *session, struct lyd_node *config,
if (diff && !lydx_get_xpathf(diff, CFG_XPATH)) if (diff && !lydx_get_xpathf(diff, CFG_XPATH))
return SR_ERR_OK; return SR_ERR_OK;
switch (event) { switch (event) {
case SR_EV_DONE: case SR_EV_DONE:
break; break;
+33 -33
View File
@@ -14,7 +14,7 @@
#include "core.h" #include "core.h"
#define ARPING_MSEC 1000 #define ARPING_MSEC 1000
#define MODULE "infix-dhcp-client" #define MODULE "infix-dhcp-client"
#define XPATH "/infix-dhcp-client:dhcp-client" #define XPATH "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/infix-dhcp-client:dhcp"
#define CACHE_TEMPLATE "/var/lib/misc/%s.cache" #define CACHE_TEMPLATE "/var/lib/misc/%s.cache"
static char *ip_cache(const char *ifname, char *str, size_t len) static char *ip_cache(const char *ifname, char *str, size_t len)
@@ -278,57 +278,57 @@ static void del(const char *ifname)
systemf("initctl -bfq delete dhcp-client-%s", ifname); systemf("initctl -bfq delete dhcp-client-%s", ifname);
} }
int infix_dhcp_client_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd) int infix_dhcp_client_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff,
sr_event_t event, struct confd *confd)
{ {
struct lyd_node *global, *cifs, *difs, *cif, *dif; struct lyd_node *ifaces, *difaces, *iface, *diface, *ipv4, *dhcp, *ddhcp;
sr_error_t err = 0; sr_error_t err = 0;
int ena = 0;
switch (event) { if (event != SR_EV_DONE)
case SR_EV_DONE:
break;
case SR_EV_CHANGE:
case SR_EV_ABORT:
default:
return SR_ERR_OK; return SR_ERR_OK;
}
global = lydx_get_descendant(config, "dhcp-client", NULL); ifaces = lydx_get_descendant(config, "interfaces", "interface", NULL);
ena = lydx_is_enabled(global, "enabled"); difaces = lydx_get_descendant(diff, "interfaces", "interface", NULL);
cifs = lydx_get_descendant(config, "dhcp-client", "client-if", NULL); /* find the modified interfaces */
difs = lydx_get_descendant(diff, "dhcp-client", "client-if", NULL); LYX_LIST_FOR_EACH(difaces, diface, "interface") {
const char *ifname = lydx_get_cattr(diface, "name");
struct lyd_node *dipv4;
/* find the modified one, delete or recreate only that */ dipv4 = lydx_get_descendant(lyd_child(diface), "ipv4", NULL);
LYX_LIST_FOR_EACH(difs, dif, "client-if") { if (!dipv4)
const char *ifname = lydx_get_cattr(dif, "if-name"); continue;
if (lydx_get_op(dif) == LYDX_OP_DELETE) { ddhcp = lydx_get_descendant(lyd_child(dipv4), "dhcp", NULL);
if (!ddhcp)
continue;
/* Check if dhcp container was deleted */
if (lydx_get_op(ddhcp) == LYDX_OP_DELETE) {
del(ifname); del(ifname);
continue; continue;
} }
LYX_LIST_FOR_EACH(cifs, cif, "client-if") { /* Find corresponding interface in config to check if dhcp is present */
if (strcmp(ifname, lydx_get_cattr(cif, "if-name"))) LYX_LIST_FOR_EACH(ifaces, iface, "interface") {
if (strcmp(ifname, lydx_get_cattr(iface, "name")))
continue; continue;
if (!ena || !lydx_is_enabled(cif, "enabled")) ipv4 = lydx_get_descendant(lyd_child(iface), "ipv4", NULL);
if (!ipv4) {
del(ifname);
break;
}
dhcp = lydx_get_descendant(lyd_child(ipv4), "dhcp", NULL);
if (!dhcp)
del(ifname); del(ifname);
else else
add(ifname, cif); add(ifname, dhcp);
break; break;
} }
} }
if (!ena) {
LYX_LIST_FOR_EACH(cifs, cif, "client-if") {
const char *ifname = lydx_get_cattr(cif, "if-name");
INFO("DHCP client globally disabled, stopping client on %s ...", ifname);
del(ifname);
}
}
return err; return err;
} }
@@ -368,7 +368,7 @@ static int cand(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
return SR_ERR_OK; return SR_ERR_OK;
} }
err = sr_dup_changes_iter(session, XPATH "/client-if//*", &iter); err = sr_dup_changes_iter(session, XPATH "//*", &iter);
if (err) if (err)
return err; return err;
+2 -2
View File
@@ -20,13 +20,13 @@ MODULES=(
"ietf-hardware@2018-03-13.yang -e hardware-state -e hardware-sensor" "ietf-hardware@2018-03-13.yang -e hardware-state -e hardware-sensor"
"infix-hardware@2025-10-30.yang" "infix-hardware@2025-10-30.yang"
"ieee802-dot1q-types@2022-10-29.yang" "ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2024-09-16.yang" "infix-ip@2025-11-02.yang"
"infix-if-type@2025-02-12.yang" "infix-if-type@2025-02-12.yang"
"infix-routing@2024-11-27.yang" "infix-routing@2024-11-27.yang"
"ieee802-dot1ab-lldp@2022-03-15.yang" "ieee802-dot1ab-lldp@2022-03-15.yang"
"infix-lldp@2025-05-05.yang" "infix-lldp@2025-05-05.yang"
"infix-dhcp-common@2025-01-29.yang" "infix-dhcp-common@2025-01-29.yang"
"infix-dhcp-client@2025-01-29.yang" "infix-dhcp-client@2025-11-02.yang"
"infix-dhcp-server@2025-10-28.yang" "infix-dhcp-server@2025-10-28.yang"
"infix-firewall@2025-04-26.yang" "infix-firewall@2025-04-26.yang"
"infix-firewall-services@2025-04-26.yang" "infix-firewall-services@2025-04-26.yang"
+15 -24
View File
@@ -6,6 +6,9 @@ module infix-dhcp-client {
import ietf-interfaces { import ietf-interfaces {
prefix if; prefix if;
} }
import ietf-ip {
prefix ip;
}
import infix-dhcp-common { import infix-dhcp-common {
prefix dhcp; prefix dhcp;
} }
@@ -13,6 +16,14 @@ module infix-dhcp-client {
contact "kernelkit@googlegroups.com"; contact "kernelkit@googlegroups.com";
description "This module implements a DHCPv4 client"; description "This module implements a DHCPv4 client";
revision 2025-11-02 {
description "Migrate DHCP client to ietf-ip augment.
- Relocate from /dhcp-client to /interfaces/interface/ipv4/dhcp
- Presence container instead of enabled leaf, matching autoconf
- Drop client-if list wrapper, not needed anymore
- Drop global enabled flag";
reference "internal, issue #1109";
}
revision 2025-01-29 { revision 2025-01-29 {
description "Consolidate DHCP options between client and server models. description "Consolidate DHCP options between client and server models.
- Rename option attribute 'name' -> 'id' - Rename option attribute 'name' -> 'id'
@@ -51,30 +62,10 @@ module infix-dhcp-client {
* Data Nodes * Data Nodes
*/ */
container dhcp-client { augment "/if:interfaces/if:interface/ip:ipv4" {
description "DHCPv4 client configuration"; container dhcp {
presence "Enable DHCP client for this interface.";
leaf enabled { description "DHCPv4 client configuration";
type boolean;
default "true";
description "Globally enables the DHCP client function.";
}
list client-if {
description "List of interfaces requesting DHCPv4 configuration.";
key "if-name";
leaf if-name {
type if:interface-ref;
mandatory true;
description "Name of the interface.";
}
leaf enabled {
type boolean;
default "true";
description "Enable DHCP client for this interface.";
}
leaf client-id { leaf client-id {
type string; type string;
+5 -5
View File
@@ -18,6 +18,10 @@ module infix-ip {
description "This module augments ietf-ip with Infix extensions and deviations."; description "This module augments ietf-ip with Infix extensions and deviations.";
revision 2025-11-02 {
description "Change autoconf to presence container, removing enabled leaf.";
reference "Internal, issue #1109.";
}
revision 2024-09-16 { revision 2024-09-16 {
description "Add support for IPv4LL request-address."; description "Add support for IPv4LL request-address.";
reference "Internal."; reference "Internal.";
@@ -36,14 +40,10 @@ module infix-ip {
*/ */
augment "/if:interfaces/if:interface/ip:ipv4" { augment "/if:interfaces/if:interface/ip:ipv4" {
container autoconf { container autoconf {
presence "Enable IPv4 link-local address autoconfiguration for this interface.";
description "Parameters to control the autoconfiguration of IPv4 address."; description "Parameters to control the autoconfiguration of IPv4 address.";
reference "RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses"; 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 { leaf request-address {
description "Try to acquire the specified IP address, if available. description "Try to acquire the specified IP address, if available.
@@ -57,9 +57,7 @@ with infamy.Test() as test:
"name": tport, "name": tport,
"enabled": True, "enabled": True,
"ipv4": { "ipv4": {
"autoconf": { "infix-ip:autoconf": {}
"enabled": True
}
} }
} }
] ]
@@ -79,8 +77,7 @@ with infamy.Test() as test:
"name": tport, "name": tport,
"enabled": True, "enabled": True,
"ipv4": { "ipv4": {
"autoconf": { "infix-ip:autoconf": {
"enabled": True,
"request-address": "169.254.42.42" "request-address": "169.254.42.42"
} }
} }
+15 -23
View File
@@ -17,7 +17,7 @@ import infamy.dhcp
from infamy.util import until, parallel from infamy.util import until, parallel
from infamy.netns import IsolatedMacVlans from infamy.netns import IsolatedMacVlans
def configure_interface(name, ip=None, prefix_length=None, forwarding=True): def configure_interface(name, ip=None, prefix_length=None, forwarding=True, dhcp=False):
interface_config = { interface_config = {
"name": name, "name": name,
"enabled": True, "enabled": True,
@@ -28,6 +28,19 @@ def configure_interface(name, ip=None, prefix_length=None, forwarding=True):
} }
if ip and prefix_length: if ip and prefix_length:
interface_config["ipv4"]["address"].append({"ip": ip, "prefix-length": prefix_length}) interface_config["ipv4"]["address"].append({"ip": ip, "prefix-length": prefix_length})
if dhcp:
interface_config["ipv4"]["infix-dhcp-client:dhcp"] = {
"option": [
{"id": "broadcast"},
{"id": "dns-server"},
{"id": "domain"},
{"id": "hostname"},
{"id": "ntp-server"},
{"id": "router"},
{"id": "netmask"}
],
"route-preference": 5
}
return interface_config return interface_config
def config_target1(target, data1, data2, link): def config_target1(target, data1, data2, link):
@@ -35,7 +48,7 @@ def config_target1(target, data1, data2, link):
"ietf-interfaces": { "ietf-interfaces": {
"interfaces": { "interfaces": {
"interface": [ "interface": [
configure_interface(data1), configure_interface(data1, dhcp=True),
configure_interface(data2, "192.168.30.1", 24), configure_interface(data2, "192.168.30.1", 24),
configure_interface(link, "192.168.50.1", 24) configure_interface(link, "192.168.50.1", 24)
] ]
@@ -61,27 +74,6 @@ def config_target1(target, data1, data2, link):
] ]
} }
} }
},
"infix-dhcp-client": {
"dhcp-client": {
"enabled": True,
"client-if": [
{
"if-name": data1,
"enabled": True,
"option": [
{"id": "broadcast"},
{"id": "dns-server"},
{"id": "domain"},
{"id": "hostname"},
{"id": "ntp-server"},
{"id": "router"},
{"id": "netmask"}
],
"route-preference": 5
}
]
}
} }
}) })
+7 -4
View File
@@ -24,13 +24,16 @@ with infamy.Test() as test:
with infamy.dhcp.Server(netns, ip=ADDRESS): with infamy.dhcp.Server(netns, ip=ADDRESS):
_, port = env.ltop.xlate("client", "data") _, port = env.ltop.xlate("client", "data")
config = { config = {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": f"{port}" "name": f"{port}",
"ipv4": {
"infix-dhcp-client:dhcp": {}
}
}] }]
} }
} }
client.put_config_dict("infix-dhcp-client", config) client.put_config_dict("ietf-interfaces", config)
with test.step("Verify client lease for 10.0.0.42"): with test.step("Verify client lease for 10.0.0.42"):
until(lambda: iface.address_exist(client, port, ADDRESS)) until(lambda: iface.address_exist(client, port, ADDRESS))
+11 -7
View File
@@ -26,16 +26,20 @@ with infamy.Test() as test:
with infamy.dhcp.Server(netns, router=ROUTER): with infamy.dhcp.Server(netns, router=ROUTER):
_, port = env.ltop.xlate("client", "data") _, port = env.ltop.xlate("client", "data")
config = { config = {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": f"{port}", "name": f"{port}",
"option": [ "ipv4": {
{"id": "router"} "infix-dhcp-client:dhcp": {
] "option": [
{"id": "router"}
]
}
}
}] }]
} }
} }
client.put_config_dict("infix-dhcp-client", config) client.put_config_dict("ietf-interfaces", config)
with test.step("Verify DHCP client has default route via 192.168.0.254"): with test.step("Verify DHCP client has default route via 192.168.0.254"):
until(lambda: route.ipv4_route_exist(client, "0.0.0.0/0", ROUTER)) until(lambda: route.ipv4_route_exist(client, "0.0.0.0/0", ROUTER))
+12 -8
View File
@@ -59,14 +59,18 @@ with infamy.Test() as test:
with test.step("Enabling DHCP client, allow option 3 and 121"): with test.step("Enabling DHCP client, allow option 3 and 121"):
_, port = env.ltop.xlate("client", "data") _, port = env.ltop.xlate("client", "data")
client.put_config_dict("infix-dhcp-client", { client.put_config_dict("ietf-interfaces", {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": f"{port}", "name": f"{port}",
"option": [ "ipv4": {
{"id": "router"}, "infix-dhcp-client:dhcp": {
{"id": "classless-static-route"} "option": [
] {"id": "router"},
{"id": "classless-static-route"}
]
}
}
}] }]
} }
}) })
+12 -8
View File
@@ -68,14 +68,18 @@ with infamy.Test() as test:
}}) }})
client.put_config_dicts({ client.put_config_dicts({
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client["link"], "name": client["link"],
"option": [ "ipv4": {
{"id": "hostname"}, "infix-dhcp-client:dhcp": {
{"id": "domain"} "option": [
] {"id": "hostname"},
{"id": "domain"}
]
}
}
}] }]
} }
}, },
+27 -19
View File
@@ -116,15 +116,19 @@ with infamy.Test() as test:
"ietf-system": { "ietf-system": {
"system": {"hostname": HOSTNM1} "system": {"hostname": HOSTNM1}
}, },
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client1["link"], "name": client1["link"],
"option": [ "ipv4": {
{"id": "router"}, "infix-dhcp-client:dhcp": {
{"id": "client-id", "hex": HOSTCID1}, "option": [
{"id": 121} {"id": "router"},
] {"id": "client-id", "hex": HOSTCID1},
{"id": 121}
]
}
}
}] }]
} }
}, },
@@ -134,16 +138,20 @@ with infamy.Test() as test:
"ietf-system": { "ietf-system": {
"system": {"hostname": HOSTNM2} "system": {"hostname": HOSTNM2}
}, },
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client2["link"], "name": client2["link"],
"client-id": HOSTCID2, "ipv4": {
"option": [ "infix-dhcp-client:dhcp": {
{"id": "router"}, "client-id": HOSTCID2,
{"id": "hostname"}, "option": [
{"id": 121} {"id": "router"},
] {"id": "hostname"},
{"id": 121}
]
}
}
}] }]
} }
}, },
+45 -33
View File
@@ -200,17 +200,21 @@ with infamy.Test() as test:
# the server is behaving correctly. # the server is behaving correctly.
client1.put_config_dicts({ client1.put_config_dicts({
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client1["server"], "name": client1["server"],
"option": [ "ipv4": {
{"id": "hostname", "value": "auto"}, "infix-dhcp-client:dhcp": {
{"id": "router"}, "option": [
{"id": "dns-server"}, {"id": "hostname", "value": "auto"},
{"id": "ntp-server"}, {"id": "router"},
{"id": 121} {"id": "dns-server"},
] {"id": "ntp-server"},
{"id": 121}
]
}
}
}] }]
} }
}, },
@@ -222,17 +226,21 @@ with infamy.Test() as test:
}}) }})
client2.put_config_dicts({ client2.put_config_dicts({
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client2["server"], "name": client2["server"],
"option": [ "ipv4": {
{"id": "hostname", "value": "auto"}, "infix-dhcp-client:dhcp": {
{"id": "router"}, "option": [
{"id": "dns-server"}, {"id": "hostname", "value": "auto"},
{"id": "ntp-server"}, {"id": "router"},
{"id": 121} {"id": "dns-server"},
] {"id": "ntp-server"},
{"id": 121}
]
}
}
}] }]
} }
}, },
@@ -244,17 +252,21 @@ with infamy.Test() as test:
}}) }})
client3.put_config_dicts({ client3.put_config_dicts({
"infix-dhcp-client": { "ietf-interfaces": {
"dhcp-client": { "interfaces": {
"client-if": [{ "interface": [{
"if-name": client3["server"], "name": client3["server"],
"option": [ "ipv4": {
{"id": "hostname", "value": "auto"}, "infix-dhcp-client:dhcp": {
{"id": "router"}, "option": [
{"id": "dns-server"}, {"id": "hostname", "value": "auto"},
{"id": "ntp-server"}, {"id": "router"},
{"id": 121} {"id": "dns-server"},
] {"id": "ntp-server"},
{"id": 121}
]
}
}
}] }]
} }
}, },
@@ -211,7 +211,6 @@ table ip nat {
"enabled": True, "enabled": True,
"forwarding": True, "forwarding": True,
"infix-ip:autoconf": { "infix-ip:autoconf": {
"enabled": True,
"request-address": "169.254.1.1" "request-address": "169.254.1.1"
} }
}, },