diff --git a/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg b/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg index aa8740c3a..eda410f60 100644 --- a/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg +++ b/board/aarch64/bananapi-bpi-r3/rootfs/usr/share/product/bananapi,bpi-r3/etc/factory-config.cfg @@ -99,7 +99,20 @@ { "name": "wan", "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", @@ -221,36 +234,6 @@ }, "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": { "option": [ { @@ -311,7 +294,7 @@ ] }, "infix-meta:meta": { - "version": "1.5" + "version": "1.6" }, "infix-services:mdns": { "enabled": true diff --git a/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/factory-config.cfg b/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/factory-config.cfg index f4511ef18..527a9f352 100644 --- a/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/factory-config.cfg +++ b/board/aarch64/friendlyarm-nanopi-r2s/rootfs/usr/share/product/friendlyarm,nanopi-r2s/etc/factory-config.cfg @@ -58,7 +58,20 @@ { "name": "wan", "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-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": { "option": [ { @@ -262,7 +245,7 @@ ] }, "infix-meta:meta": { - "version": "1.5" + "version": "1.6" }, "infix-services:mdns": { "enabled": true diff --git a/board/aarch64/raspberrypi-rpi64/rootfs/usr/share/product/raspberrypi,4-model-b/etc/factory-config.cfg b/board/aarch64/raspberrypi-rpi64/rootfs/usr/share/product/raspberrypi,4-model-b/etc/factory-config.cfg index 42ae38cc6..3d9c69bab 100644 --- a/board/aarch64/raspberrypi-rpi64/rootfs/usr/share/product/raspberrypi,4-model-b/etc/factory-config.cfg +++ b/board/aarch64/raspberrypi-rpi64/rootfs/usr/share/product/raspberrypi,4-model-b/etc/factory-config.cfg @@ -37,7 +37,20 @@ }, { "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", @@ -157,38 +170,8 @@ }, "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": { - "version": "1.5" + "version": "1.6" }, "infix-services:mdns": { "enabled": true diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index bb9fffadb..bcae00078 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -9,6 +9,12 @@ All notable changes to the project are documented in this file. ### Changes - 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: - The NanoPi R2S bootloader is now automatically built and uploaded to the [`latest-boot` release][lastest-boot] tag diff --git a/doc/networking.md b/doc/networking.md index b6db43fd7..64e0d7d5b 100644 --- a/doc/networking.md +++ b/doc/networking.md @@ -996,7 +996,7 @@ default. admin@example:/> configure 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 autoconf enabled true + admin@example:/config/interface/eth0/ipv4/> set autoconf admin@example:/config/interface/eth0/ipv4/> diff +interfaces { + interface eth0 { @@ -1004,9 +1004,7 @@ default. + address 10.0.1.1 { + prefix-length 24; + } - + autoconf { - + enabled true; - + } + + autoconf; + } + } +} @@ -1022,15 +1020,18 @@ default. ipv6 ::1/128 (static) admin@example:/> -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]). +As shown, the link-local IPv4 address is configured with `set autoconf`. +The presence of the `autoconf` container enables IPv4 link-local address +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 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 + 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 @@ -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) admin@example:/> configure - admin@example:/config/> edit dhcp-client - admin@example:/config/dhcp-client/> set client-if eth0 - admin@example:/config/dhcp-client/> leave + admin@example:/config/> edit interface eth0 ipv4 + admin@example:/config/interface/eth0/ipv4/> set dhcp + admin@example:/config/interface/eth0/ipv4/> leave admin@example:/> show interfaces INTERFACE PROTOCOL STATE DATA 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*. +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) diff --git a/doc/scripting-sysrepocfg.md b/doc/scripting-sysrepocfg.md index 312fd6ab4..078a2e537 100644 --- a/doc/scripting-sysrepocfg.md +++ b/doc/scripting-sysrepocfg.md @@ -173,11 +173,13 @@ Enabling DHCPv4 client on interface *e0*, with current default options. ``` ~$ cat /tmp/file.json { - "infix-dhcp-client:dhcp-client": { - "enabled": true, - "client-if": [ + "ietf-interfaces:interfaces": { + "interface": [ { - "if-name": "e0" + "name": "e0", + "ietf-ip:ipv4": { + "infix-dhcp-client:dhcp": {} + } } ] } @@ -187,41 +189,27 @@ 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 { - "infix-dhcp-client:dhcp-client": { - "enabled": false - } -} -~$ scp file.json admin@example.local:/tmp/file.json -~$ ssh admin@example.local 'sysrepocfg -E /tmp/file.json -fjson -d running' -~$ -``` - -Configuration for client interface *e0* remains, but does not apply as -DHCPv4 is disabled. - -``` -admin@example:~$ sysrepocfg -X -fjson -d running -x "/infix-dhcp-client:dhcp-client" -{ - "infix-dhcp-client:dhcp-client": { - "enabled": false, - "client-if": [ + "ietf-interfaces:interfaces": { + "interface": [ { - "if-name": "e0" + "name": "e0", + "ietf-ip:ipv4": {} } ] } } -admin@example:~$ +~$ scp file.json admin@example.local:/tmp/file.json +~$ ssh admin@example.local 'sysrepocfg -E /tmp/file.json -fjson -d running' +~$ ``` -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. +To fully remove the DHCPv4 client configuration, remove the `infix-dhcp-client:dhcp` +container from the interface's ipv4 configuration. ## Enable/Disable IPv6 diff --git a/package/confd/confd.mk b/package/confd/confd.mk index 96024a1f0..ed74875bf 100644 --- a/package/confd/confd.mk +++ b/package/confd/confd.mk @@ -4,7 +4,7 @@ # ################################################################################ -CONFD_VERSION = 1.5 +CONFD_VERSION = 1.6 CONFD_SITE_METHOD = local CONFD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/confd CONFD_LICENSE = BSD-3-Clause diff --git a/src/confd/bin/gen-interfaces b/src/confd/bin/gen-interfaces index cad922c23..19d343855 100755 --- a/src/confd/bin/gen-interfaces +++ b/src/confd/bin/gen-interfaces @@ -169,9 +169,23 @@ if [ -n "$bridge" ]; then "name": "$bridge", "type": "infix-if-type:bridge", "ietf-ip:ipv4": { - "infix-ip:autoconf": { - "enabled": $ipv4 - } +EOF + if [ "$ipv4" = "true" ]; then + cat < "$temp" && mv "$temp" "$file" diff --git a/src/confd/share/migrate/1.6/20-autoconf-to-presence.sh b/src/confd/share/migrate/1.6/20-autoconf-to-presence.sh new file mode 100755 index 000000000..988a43522 --- /dev/null +++ b/src/confd/share/migrate/1.6/20-autoconf-to-presence.sh @@ -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" diff --git a/src/confd/share/migrate/1.6/Makefile.am b/src/confd/share/migrate/1.6/Makefile.am new file mode 100644 index 000000000..c3a250a5a --- /dev/null +++ b/src/confd/share/migrate/1.6/Makefile.am @@ -0,0 +1,3 @@ +migratedir = $(pkgdatadir)/migrate/1.6 +dist_migrate_DATA = 10-dhcp-client-to-ipv4.sh \ + 20-autoconf-to-presence.sh diff --git a/src/confd/share/migrate/Makefile.am b/src/confd/share/migrate/Makefile.am index 63b1adf73..c5d75c31b 100644 --- a/src/confd/share/migrate/Makefile.am +++ b/src/confd/share/migrate/Makefile.am @@ -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 diff --git a/src/confd/src/core.c b/src/confd/src/core.c index 4fbf1bebb..f452df355 100644 --- a/src/confd/src/core.c +++ b/src/confd/src/core.c @@ -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_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); if (rc != SR_ERR_OK) { 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; /* infix-containers */ +#ifdef CONTAINERS if ((rc = infix_containers_change(session, config, diff, event, confd))) goto free_diff; +#endif /* ietf-hardware */ 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))) goto free_diff; + /* infix-meta */ + if ((rc = infix_meta_change_cb(session, config, diff, event, confd))) + goto free_diff; + if (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); if (rc) goto err; +#ifdef CONTAINERS rc = infix_containers_rpc_init(&confd); if (rc) goto err; +#endif rc = infix_dhcp_server_rpc_init(&confd); if (rc) goto err; @@ -407,6 +415,10 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) goto err; /* Candidate infer configurations */ + rc = ietf_interfaces_cand_init(&confd); + if (rc) + goto err; + rc = ietf_hardware_candidate_init(&confd); if (rc) goto err; diff --git a/src/confd/src/core.h b/src/confd/src/core.h index d7c2f2e0d..87f598497 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -226,7 +226,7 @@ int infix_factory_rpc_init(struct confd *confd); int ietf_factory_default_rpc_init(struct confd *confd); /* 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 */ int infix_system_sw_rpc_init(struct confd *confd); diff --git a/src/confd/src/ietf-ip.c b/src/confd/src/ietf-ip.c index a428967b1..adcf9cb86 100644 --- a/src/confd/src/ietf-ip.c +++ b/src/confd/src/ietf-ip.c @@ -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... */ zcip = lydx_get_child(ipconf, "autoconf"); - if (zcip && lydx_is_enabled(zcip, "enabled")) { + if (zcip) { struct lyd_node *node; const char *addr; int diff = 0; @@ -105,9 +105,8 @@ int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif, if (node) { const struct lyd_node *tmp; - tmp = lydx_get_child(node, "enabled"); - if (tmp) - diff++; + /* presence container created or deleted */ + diff++; tmp = lydx_get_child(node, "request-address"); if (tmp) diff++; diff --git a/src/confd/src/infix-containers.c b/src/confd/src/infix-containers.c index e73f325c0..359ef320c 100644 --- a/src/confd/src/infix-containers.c +++ b/src/confd/src/infix-containers.c @@ -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)) return SR_ERR_OK; + switch (event) { case SR_EV_DONE: break; diff --git a/src/confd/src/infix-dhcp-client.c b/src/confd/src/infix-dhcp-client.c index 5310d6bfc..c2da13b81 100644 --- a/src/confd/src/infix-dhcp-client.c +++ b/src/confd/src/infix-dhcp-client.c @@ -14,7 +14,7 @@ #include "core.h" #define ARPING_MSEC 1000 #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" 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); } -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; - int ena = 0; - switch (event) { - case SR_EV_DONE: - break; - case SR_EV_CHANGE: - case SR_EV_ABORT: - default: + if (event != SR_EV_DONE) return SR_ERR_OK; - } - global = lydx_get_descendant(config, "dhcp-client", NULL); - ena = lydx_is_enabled(global, "enabled"); + ifaces = lydx_get_descendant(config, "interfaces", "interface", NULL); + difaces = lydx_get_descendant(diff, "interfaces", "interface", NULL); + + /* find the modified interfaces */ + LYX_LIST_FOR_EACH(difaces, diface, "interface") { + const char *ifname = lydx_get_cattr(diface, "name"); + struct lyd_node *dipv4; - cifs = lydx_get_descendant(config, "dhcp-client", "client-if", NULL); - difs = lydx_get_descendant(diff, "dhcp-client", "client-if", NULL); + dipv4 = lydx_get_descendant(lyd_child(diface), "ipv4", NULL); + if (!dipv4) + continue; - /* find the modified one, delete or recreate only that */ - LYX_LIST_FOR_EACH(difs, dif, "client-if") { - const char *ifname = lydx_get_cattr(dif, "if-name"); + ddhcp = lydx_get_descendant(lyd_child(dipv4), "dhcp", NULL); + if (!ddhcp) + continue; - if (lydx_get_op(dif) == LYDX_OP_DELETE) { + /* Check if dhcp container was deleted */ + if (lydx_get_op(ddhcp) == LYDX_OP_DELETE) { del(ifname); continue; } - LYX_LIST_FOR_EACH(cifs, cif, "client-if") { - if (strcmp(ifname, lydx_get_cattr(cif, "if-name"))) + /* Find corresponding interface in config to check if dhcp is present */ + LYX_LIST_FOR_EACH(ifaces, iface, "interface") { + if (strcmp(ifname, lydx_get_cattr(iface, "name"))) 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); else - add(ifname, cif); + add(ifname, dhcp); 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; } @@ -368,7 +368,7 @@ static int cand(sr_session_ctx_t *session, uint32_t sub_id, const char *module, return SR_ERR_OK; } - err = sr_dup_changes_iter(session, XPATH "/client-if//*", &iter); + err = sr_dup_changes_iter(session, XPATH "//*", &iter); if (err) return err; diff --git a/src/confd/yang/confd.inc b/src/confd/yang/confd.inc index 03b03a70a..cb0056564 100644 --- a/src/confd/yang/confd.inc +++ b/src/confd/yang/confd.inc @@ -20,13 +20,13 @@ MODULES=( "ietf-hardware@2018-03-13.yang -e hardware-state -e hardware-sensor" "infix-hardware@2025-10-30.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-routing@2024-11-27.yang" "ieee802-dot1ab-lldp@2022-03-15.yang" "infix-lldp@2025-05-05.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-firewall@2025-04-26.yang" "infix-firewall-services@2025-04-26.yang" diff --git a/src/confd/yang/confd/infix-dhcp-client.yang b/src/confd/yang/confd/infix-dhcp-client.yang index 872e7af1b..9abe21fad 100644 --- a/src/confd/yang/confd/infix-dhcp-client.yang +++ b/src/confd/yang/confd/infix-dhcp-client.yang @@ -6,6 +6,9 @@ module infix-dhcp-client { import ietf-interfaces { prefix if; } + import ietf-ip { + prefix ip; + } import infix-dhcp-common { prefix dhcp; } @@ -13,6 +16,14 @@ module infix-dhcp-client { contact "kernelkit@googlegroups.com"; 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 { description "Consolidate DHCP options between client and server models. - Rename option attribute 'name' -> 'id' @@ -51,30 +62,10 @@ module infix-dhcp-client { * Data Nodes */ - container dhcp-client { - description "DHCPv4 client configuration"; - - leaf enabled { - 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."; - } + augment "/if:interfaces/if:interface/ip:ipv4" { + container dhcp { + presence "Enable DHCP client for this interface."; + description "DHCPv4 client configuration"; leaf client-id { type string; diff --git a/src/confd/yang/confd/infix-dhcp-client@2025-01-29.yang b/src/confd/yang/confd/infix-dhcp-client@2025-11-02.yang similarity index 100% rename from src/confd/yang/confd/infix-dhcp-client@2025-01-29.yang rename to src/confd/yang/confd/infix-dhcp-client@2025-11-02.yang diff --git a/src/confd/yang/confd/infix-ip.yang b/src/confd/yang/confd/infix-ip.yang index 88a1c93fc..094a972ae 100644 --- a/src/confd/yang/confd/infix-ip.yang +++ b/src/confd/yang/confd/infix-ip.yang @@ -18,6 +18,10 @@ module infix-ip { 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 { description "Add support for IPv4LL request-address."; reference "Internal."; @@ -36,14 +40,10 @@ module infix-ip { */ augment "/if:interfaces/if:interface/ip:ipv4" { container autoconf { + presence "Enable IPv4 link-local address autoconfiguration for this interface."; 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. diff --git a/src/confd/yang/confd/infix-ip@2024-09-16.yang b/src/confd/yang/confd/infix-ip@2025-11-02.yang similarity index 100% rename from src/confd/yang/confd/infix-ip@2024-09-16.yang rename to src/confd/yang/confd/infix-ip@2025-11-02.yang diff --git a/test/case/ietf_interfaces/ipv4_autoconf/test.py b/test/case/ietf_interfaces/ipv4_autoconf/test.py index a1e59f709..5555758ab 100755 --- a/test/case/ietf_interfaces/ipv4_autoconf/test.py +++ b/test/case/ietf_interfaces/ipv4_autoconf/test.py @@ -57,9 +57,7 @@ def no_linklocal(target, iface): "name": tport, "enabled": True, "ipv4": { - "autoconf": { - "enabled": True - } + "infix-ip:autoconf": {} } } ] @@ -79,8 +77,7 @@ def no_linklocal(target, iface): "name": tport, "enabled": True, "ipv4": { - "autoconf": { - "enabled": True, + "infix-ip:autoconf": { "request-address": "169.254.42.42" } } diff --git a/test/case/ietf_routing/route_pref_dhcp/test.py b/test/case/ietf_routing/route_pref_dhcp/test.py index d98b1ab6a..f9ba39e5f 100755 --- a/test/case/ietf_routing/route_pref_dhcp/test.py +++ b/test/case/ietf_routing/route_pref_dhcp/test.py @@ -17,7 +17,7 @@ from infamy.util import until, parallel 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 = { "name": name, "enabled": True, @@ -28,6 +28,19 @@ def configure_interface(name, ip=None, prefix_length=None, forwarding=True): } if ip and 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 def config_target1(target, data1, data2, link): @@ -35,7 +48,7 @@ def config_target1(target, data1, data2, link): "ietf-interfaces": { "interfaces": { "interface": [ - configure_interface(data1), + configure_interface(data1, dhcp=True), configure_interface(data2, "192.168.30.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 - } - ] - } } }) diff --git a/test/case/infix_dhcp/client_basic/test.py b/test/case/infix_dhcp/client_basic/test.py index afe0a3915..822b49fcd 100755 --- a/test/case/infix_dhcp/client_basic/test.py +++ b/test/case/infix_dhcp/client_basic/test.py @@ -24,13 +24,16 @@ with infamy.dhcp.Server(netns, ip=ADDRESS): _, port = env.ltop.xlate("client", "data") config = { - "dhcp-client": { - "client-if": [{ - "if-name": f"{port}" + "interfaces": { + "interface": [{ + "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"): until(lambda: iface.address_exist(client, port, ADDRESS)) diff --git a/test/case/infix_dhcp/client_default_gw/test.py b/test/case/infix_dhcp/client_default_gw/test.py index 2837b0c0c..7d16cd567 100755 --- a/test/case/infix_dhcp/client_default_gw/test.py +++ b/test/case/infix_dhcp/client_default_gw/test.py @@ -26,16 +26,20 @@ with infamy.dhcp.Server(netns, router=ROUTER): _, port = env.ltop.xlate("client", "data") config = { - "dhcp-client": { - "client-if": [{ - "if-name": f"{port}", - "option": [ - {"id": "router"} - ] + "interfaces": { + "interface": [{ + "name": f"{port}", + "ipv4": { + "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"): until(lambda: route.ipv4_route_exist(client, "0.0.0.0/0", ROUTER)) diff --git a/test/case/infix_dhcp/client_routes/test.py b/test/case/infix_dhcp/client_routes/test.py index 62d139cc1..26736d6d8 100755 --- a/test/case/infix_dhcp/client_routes/test.py +++ b/test/case/infix_dhcp/client_routes/test.py @@ -59,14 +59,18 @@ with test.step("Enabling DHCP client, allow option 3 and 121"): _, port = env.ltop.xlate("client", "data") - client.put_config_dict("infix-dhcp-client", { - "dhcp-client": { - "client-if": [{ - "if-name": f"{port}", - "option": [ - {"id": "router"}, - {"id": "classless-static-route"} - ] + client.put_config_dict("ietf-interfaces", { + "interfaces": { + "interface": [{ + "name": f"{port}", + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "router"}, + {"id": "classless-static-route"} + ] + } + } }] } }) diff --git a/test/case/infix_dhcp/server_basic/test.py b/test/case/infix_dhcp/server_basic/test.py index 42ff3fb37..164f5f9b6 100755 --- a/test/case/infix_dhcp/server_basic/test.py +++ b/test/case/infix_dhcp/server_basic/test.py @@ -68,14 +68,18 @@ def verify_hostname(dut, hostname): }}) client.put_config_dicts({ - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client["link"], - "option": [ - {"id": "hostname"}, - {"id": "domain"} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client["link"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "hostname"}, + {"id": "domain"} + ] + } + } }] } }, diff --git a/test/case/infix_dhcp/server_host/test.py b/test/case/infix_dhcp/server_host/test.py index 32f622d73..03187716a 100755 --- a/test/case/infix_dhcp/server_host/test.py +++ b/test/case/infix_dhcp/server_host/test.py @@ -116,15 +116,19 @@ "ietf-system": { "system": {"hostname": HOSTNM1} }, - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client1["link"], - "option": [ - {"id": "router"}, - {"id": "client-id", "hex": HOSTCID1}, - {"id": 121} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client1["link"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "router"}, + {"id": "client-id", "hex": HOSTCID1}, + {"id": 121} + ] + } + } }] } }, @@ -134,16 +138,20 @@ "ietf-system": { "system": {"hostname": HOSTNM2} }, - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client2["link"], - "client-id": HOSTCID2, - "option": [ - {"id": "router"}, - {"id": "hostname"}, - {"id": 121} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client2["link"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "client-id": HOSTCID2, + "option": [ + {"id": "router"}, + {"id": "hostname"}, + {"id": 121} + ] + } + } }] } }, diff --git a/test/case/infix_dhcp/server_subnets/test.py b/test/case/infix_dhcp/server_subnets/test.py index d7b380e45..c4267d6cf 100755 --- a/test/case/infix_dhcp/server_subnets/test.py +++ b/test/case/infix_dhcp/server_subnets/test.py @@ -200,17 +200,21 @@ def has_system_servers(dut, dns, ntp=None): # the server is behaving correctly. client1.put_config_dicts({ - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client1["server"], - "option": [ - {"id": "hostname", "value": "auto"}, - {"id": "router"}, - {"id": "dns-server"}, - {"id": "ntp-server"}, - {"id": 121} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client1["server"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "hostname", "value": "auto"}, + {"id": "router"}, + {"id": "dns-server"}, + {"id": "ntp-server"}, + {"id": 121} + ] + } + } }] } }, @@ -222,17 +226,21 @@ def has_system_servers(dut, dns, ntp=None): }}) client2.put_config_dicts({ - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client2["server"], - "option": [ - {"id": "hostname", "value": "auto"}, - {"id": "router"}, - {"id": "dns-server"}, - {"id": "ntp-server"}, - {"id": 121} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client2["server"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "hostname", "value": "auto"}, + {"id": "router"}, + {"id": "dns-server"}, + {"id": "ntp-server"}, + {"id": 121} + ] + } + } }] } }, @@ -244,17 +252,21 @@ def has_system_servers(dut, dns, ntp=None): }}) client3.put_config_dicts({ - "infix-dhcp-client": { - "dhcp-client": { - "client-if": [{ - "if-name": client3["server"], - "option": [ - {"id": "hostname", "value": "auto"}, - {"id": "router"}, - {"id": "dns-server"}, - {"id": "ntp-server"}, - {"id": 121} - ] + "ietf-interfaces": { + "interfaces": { + "interface": [{ + "name": client3["server"], + "ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + {"id": "hostname", "value": "auto"}, + {"id": "router"}, + {"id": "dns-server"}, + {"id": "ntp-server"}, + {"id": 121} + ] + } + } }] } }, diff --git a/test/case/use_case/ospf_container/test.py b/test/case/use_case/ospf_container/test.py index 3b4c11a5f..968f37e28 100755 --- a/test/case/use_case/ospf_container/test.py +++ b/test/case/use_case/ospf_container/test.py @@ -211,7 +211,6 @@ def config_generic(target, router, ring1, ring2, link): "enabled": True, "forwarding": True, "infix-ip:autoconf": { - "enabled": True, "request-address": "169.254.1.1" } },