Compare commits

...
8 Commits
Author SHA1 Message Date
Joachim Wiberg 226ea49e7c confd: fix annoying warning in log
This fixes the annoying libyang warning after commit da29771.

    confd[3375]: libyang[0]: Invalid argument ctx_node (lyd_find_xpath()).

This happens when the diff is used in the wrong event when it is NULL.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 21:19:41 +01:00
Joachim Wiberg cb633a78d6 confd: minor coding style fixes and refactoring
Collapse, simplify, and break up ietf_keystore_change() into multiple
functions.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 21:19:41 +01:00
Joachim Wiberg d2e55eadf8 board/common: check if partition/LABEL is available
Check if partition/LABEL is available before trying to run tune2fs and
mount commands on it.  This change masks the kernel output:

    LABEL=var: Can't lookup blockdev

commne when running `make run` on x86_64 builds.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 21:19:40 +01:00
Joachim Wiberg 70d51420c9 board/common: fix scary boot warnings, follow-up to 45efa94
In 45efa94 we introduced new mount options for the: 'aux', 'cfg', and
'var' partitions.  To save boot time, we also disabled the periodic fsck
check, which does not affect journal replay or other Ext4 safety or
integrity checks.  The latter involved calling tune2fs at runtime, but
this caused the following to appear for the 'aux' partition, which is an
ext2 for systems that need to change U-Boot settings, e.g., to set MAC
address on systems without a VPD.

   EXT4-fs: Mount option(s) incompatible with ext2

To make matters worse, the new mount option(s), e.g., 'commit=30', gave
us another set of warnings from the kernel.  This was due to the fstype
being 'auto', so the kernel objected to options not being applicable to
every filesystem it tried before ending up with extfs:

    squashfs: Unknown parameter 'commit'
    vfat: Unknown parameter 'commit'
    exfat: Unknown parameter 'commit'
    fuseblk: Unknown parameter 'commit'
    btrfs: Unknown parameter 'errors'

This commit explicitly sets aux to ext2, and the others to ext4, and it
now checks before calling tune2fs that the partition/disk image is ext4.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 21:19:40 +01:00
Joachim Wiberg 1e80b20856 board/common: utilize new finit-style logging for factory reset
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 21:19:39 +01:00
Joachim Wiberg 918353dcc7 confd: drop 'enabled' node from IPv4 autoconf container
Neither the IPv6 autonconf container, nor the recently moved DHCP client
container have an 'enabled' flag.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 14:12:10 +01:00
Joachim Wiberg d53a35b867 confd: relocate /dhcp-client to /interfaces/interface/ipv4/dhcp
Please note, this change drops not only the global enabled flag, but also the
per-interface enabled flag, converting it to a presence container.  The name
of the container is also shortened from dhcp-client -> dhcp.  A pattern that
expected to be reused also for the DHCPv6 client.

Fixes #1109

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 14:11:53 +01:00
Joachim Wiberg 331f60be64 confd: minor, silence libyang warning when built w/o containers
Silence confd[3582]: libyang[0]: Invalid argument ctx_node (lyd_find_xpath())
warning in syslog.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-02 11:38:58 +01:00
36 changed files with 577 additions and 459 deletions
@@ -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
@@ -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
@@ -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
+6 -6
View File
@@ -15,9 +15,9 @@ cfgfs /config configfs nofail,noauto 0 0
# The chosen backing storage for the overlays placed on /cfg, /etc,
# /home, /root, and /var, are determined dynamically by /usr/libexec/infix/mnt
# depending on the available devices.
mnttmp /mnt/tmp tmpfs defaults 0 0
LABEL=aux /mnt/aux auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
LABEL=var /mnt/var auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
LABEL=cfg /mnt/cfg auto noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
hostfs /mnt/host 9p cache=none,msize=16384,noauto 0 0
/usr/libexec/infix/mnt# /cfg helper none 0 0
mnttmp /mnt/tmp tmpfs defaults 0 0
LABEL=aux /mnt/aux ext2 noatime,nodiratime,noauto,errors=remount-ro 0 0
LABEL=var /mnt/var ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
LABEL=cfg /mnt/cfg ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
hostfs /mnt/host 9p cache=none,msize=16384,noauto 0 0
/usr/libexec/infix/mnt# /cfg helper none 0 0
+46 -12
View File
@@ -44,12 +44,15 @@ check_factory()
factory_reset()
{
find /sys/class/leds/ -type l -exec sh -c 'echo 100 > $0/brightness' {} \;
logger $opt -p user.crit -t "$nm" "Resetting to factory defaults."
print_start "Resetting to factory defaults."
logger $opt -p user.notice -t "$nm" "Resetting to factory defaults."
rm -rf /mnt/cfg/* /mnt/var/*
logger $opt -p user.crit -t "$nm" "Factory reset complete."
sync
logger $opt -p user.notice -t "$nm" "Factory reset complete."
print_end 0 "Factory reset complete."
print_restore
}
is_mmc()
@@ -105,15 +108,18 @@ find_partition_by_label()
esac
disk="/dev/$devname"
#
# 1. Try GPT/MBR partition label using sgdisk
#
result=$(sgdisk -p "$disk" 2>/dev/null | awk -v label="$label" -v devname="$devname" '
/^ *[0-9]/ {
/^ *[0-9]/ {
if ($7 == label) {
if (devname ~ /^(mmcblk|nvme|loop)/) {
print devname "p" $1
} else {
print devname $1
}
exit 0
if (devname ~ /^(mmcblk|nvme|loop)/)
print devname "p" $1;
else
print devname $1;
exit 0;
}
}
')
@@ -122,7 +128,30 @@ find_partition_by_label()
echo "$result"
return 0
fi
#
# 2. Fallback: Check if the whole disk is an ext4/ext2/ext3 filesystem
#
# Check for ext4/ext2/ext3 magic number (0xEF53) at offset 1080 (1024+56).
magic_number=$(dd if="$disk" bs=1 skip=1080 count=2 2>/dev/null | od -t x2 -A n | tr -d ' \n')
# Check for both Little-Endian ('53ef') and Big-Endian ('ef53') interpretations of 0xEF53.
# This supports bi-endian architectures like MIPS that may run in BE mode,
# as well as the LE mode which is standard for RISC-V and ext filesystems.
if [ "$magic_number" = "ef53" ] || [ "$magic_number" = "53ef" ]; then
# Read the volume label from offset 1144 (1024+120)
fslabel=$(dd if="$disk" bs=1 skip=1144 count=16 2>/dev/null | tr -d '\000')
logger $opt -p user.notice -t "$nm" "Found label $fslabel on disk $disk ..."
if [ "$fslabel" = "$label" ]; then
echo "$devname"
return 0
fi
fi
done
return 1
}
@@ -273,6 +302,9 @@ mount_rw()
# If something is already setup, leave it be.
mountpoint -q "/$1" && return 0
# If partition doesn't exist (var is optional), signal caller.
find_partition_by_label "$1" >/dev/null || return 1
# Check if /var has been resized to fill the sdcard/eMMC
if [ "$1" = "var" ] && is_mmc; then
if [ -f /mnt/aux/resized ] || [ -f /mnt/aux/resized.failed ]; then
@@ -289,8 +321,10 @@ mount_rw()
# TODO: Also look for UBI partitions
#
tune2fs -c 0 -i 0 LABEL="$1" 2>/dev/null
# Disable periodic fsck, yet keeping safety checks on ext4
if grep "LABEL=$label" /etc/fstab |grep -q ext4; then
tune2fs -c 0 -i 0 LABEL="$1" 2>/dev/null
fi
mount LABEL="$1" 2>/dev/null && return 0
return 1
+6
View File
@@ -8,6 +8,12 @@ All notable changes to the project are documented in this file.
### Changes
- 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
+37 -11
View File
@@ -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)
+16 -28
View File
@@ -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,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
{
"infix-dhcp-client:dhcp-client": {
"enabled": false
"ietf-interfaces:interfaces": {
"interface": [
{
"name": "e0",
"ietf-ip:ipv4": {}
}
]
}
}
~$ 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
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": [
{
"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.
To fully remove the DHCPv4 client configuration, remove the `infix-dhcp-client:dhcp`
container from the interface's ipv4 configuration.
## 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 = $(BR2_EXTERNAL_INFIX_PATH)/src/confd
CONFD_LICENSE = BSD-3-Clause
+17 -15
View File
@@ -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 <<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": {
"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)
]
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
}
}
+2 -1
View File
@@ -1,6 +1,6 @@
AC_PREREQ(2.61)
# 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_SILENT_RULES(yes)
@@ -19,6 +19,7 @@ AC_CONFIG_FILES([
share/migrate/1.3/Makefile
share/migrate/1.4/Makefile
share/migrate/1.5/Makefile
share/migrate/1.6/Makefile
yang/Makefile
yang/confd/Makefile
yang/test-mode/Makefile
+38
View File
@@ -0,0 +1,38 @@
#!/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
file=$1
temp=${file}.tmp
jq '
if .["infix-dhcp-client:dhcp-client"] then
.["infix-dhcp-client:dhcp-client"]."client-if" as $clients |
($clients // [] | map({
key: ."if-name",
value: {
"infix-dhcp-client:dhcp": (
. | del(."if-name") | del(.enabled)
)
}
}) | from_entries) as $dhcp_configs |
if .["ietf-interfaces:interfaces"] then
.["ietf-interfaces:interfaces"].interface |= map(
if $dhcp_configs[.name] then
.["ietf-ip:ipv4"] += $dhcp_configs[.name]
else
.
end
)
else
.
end |
del(.["infix-dhcp-client:dhcp-client"])
else
.
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
+17 -8
View File
@@ -8,8 +8,8 @@
struct confd confd;
int core_startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
static int core_startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
{
sr_event_t last_event = -1;
static unsigned int last_request = -1;
@@ -221,8 +221,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)))
@@ -258,16 +260,21 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
AUDIT("The new configuration has been applied.");
}
free_diff:
lyd_free_tree(diff);
return rc;
lyd_free_tree(diff);
return rc;
}
static inline int subscribe_module(char *model, struct confd *confd, int flags) {
return sr_module_change_subscribe(confd->session, model, "//.", change_cb, confd,
CB_PRIO_PRIMARY, SR_SUBSCR_CHANGE_ALL_MODULES | SR_SUBSCR_DEFAULT | flags, &confd->sub) &&
static inline int subscribe_module(char *model, struct confd *confd, int flags)
{
ERROR("core: subscribing to models");
return sr_module_change_subscribe(confd->session, model, "//.", change_cb, confd,
CB_PRIO_PRIMARY, SR_SUBSCR_CHANGE_ALL_MODULES |
SR_SUBSCR_DEFAULT | flags, &confd->sub) &&
sr_module_change_subscribe(confd->startup, model, "//.", core_startup_save, NULL,
CB_PRIO_PASSIVE, SR_SUBSCR_PASSIVE | SR_SUBSCR_CHANGE_ALL_MODULES, &confd->sub);
CB_PRIO_PASSIVE, SR_SUBSCR_CHANGE_ALL_MODULES |
SR_SUBSCR_PASSIVE, &confd->sub);
}
int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
@@ -385,9 +392,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;
-1
View File
@@ -135,7 +135,6 @@ struct confd {
struct dagger netdag;
};
int core_startup_save (sr_session_ctx_t *, uint32_t, const char *, const char *, sr_event_t, unsigned, void *);
static inline int register_change(sr_session_ctx_t *session, const char *module, const char *xpath,
int flags, sr_module_change_cb cb, void *arg, sr_subscription_ctx_t **sub)
+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...
*/
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++;
+119 -100
View File
@@ -51,89 +51,122 @@ static char *filerd(const char *fn, size_t len)
return buf;
}
int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
static int gen_hostkey(const char *name, struct lyd_node *change)
{
const char *private_key, *public_key;
int rc = SR_ERR_OK;
private_key = lydx_get_cattr(change, "cleartext-private-key");
public_key = lydx_get_cattr(change, "public-key");
if (mkdir(SSH_HOSTKEYS_NEXT, 0600) && (errno != EEXIST)) {
ERRNO("Failed creating %s", SSH_HOSTKEYS_NEXT);
rc = SR_ERR_INTERNAL;
}
if (systemf("/usr/libexec/infix/mksshkey %s %s %s %s", name, SSH_HOSTKEYS_NEXT, public_key, private_key))
rc = SR_ERR_INTERNAL;
return rc;
}
static int keystore_update(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff)
{
const char *xpath = "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key";
sr_val_t *list = NULL;
size_t count = 0;
int rc;
rc = sr_get_items(session, xpath, 0, 0, &list, &count);
if (rc != SR_ERR_OK) {
ERROR("Cannot find any asymmetric keys in configuration");
return 0;
}
for (size_t i = 0; i < count; i++) {
char *name = srx_get_str(session, "%s/name", list[i].xpath);
char *public_key_format, *private_key_format;
char *pub_key = NULL, *priv_key = NULL;
sr_val_t *entry = &list[i];
if (srx_isset(session, "%s/cleartext-private-key", entry->xpath) ||
srx_isset(session, "%s/public-key", entry->xpath))
continue;
public_key_format = srx_get_str(session, "%s/public-key-format", entry->xpath);
if (!public_key_format)
continue;
private_key_format = srx_get_str(session, "%s/private-key-format", entry->xpath);
if (!private_key_format) {
free(public_key_format);
continue;
}
if (strcmp(private_key_format, "infix-crypto-types:rsa-private-key-format") ||
strcmp(public_key_format, "infix-crypto-types:ssh-public-key-format"))
continue;
NOTE("SSH key (%s) does not exist, generating...", name);
if (systemf("/usr/libexec/infix/mkkeys %s %s", SSH_PRIVATE_KEY, SSH_PUBLIC_KEY)) {
ERROR("Failed generating SSH keys for %s", name);
goto next;
}
priv_key = filerd(SSH_PRIVATE_KEY, filesz(SSH_PRIVATE_KEY));
if (!priv_key)
goto next;
pub_key = filerd(SSH_PUBLIC_KEY, filesz(SSH_PUBLIC_KEY));
if (!pub_key)
goto next;
rc = srx_set_str(session, priv_key, 0, "%s/cleartext-private-key", entry->xpath);
if (rc) {
ERROR("Failed setting private key for %s... rc: %d", name, rc);
goto next;
}
rc = srx_set_str(session, pub_key, 0, "%s/public-key", entry->xpath);
if (rc != SR_ERR_OK) {
ERROR("Failed setting public key for %s... rc: %d", name, rc);
goto next;
}
next:
if (erase(SSH_PRIVATE_KEY))
ERRNO("Failed removing SSH server private key");
if (erase(SSH_PUBLIC_KEY))
ERRNO("Failed removing SSH server public key");
if (priv_key)
free(priv_key);
if (pub_key)
free(pub_key);
free(name);
free(public_key_format);
free(private_key_format);
}
if (list)
sr_free_values(list, count);
return 0;
}
int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff,
sr_event_t event, struct confd *confd)
{
struct lyd_node *changes, *change;
sr_val_t *list = NULL;
int rc = SR_ERR_OK;
size_t count = 0;
if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_))
return SR_ERR_OK;
switch (event) {
case SR_EV_UPDATE:
rc = sr_get_items(session, "/ietf-keystore:keystore/asymmetric-keys/asymmetric-key", 0, 0, &list, &count);
if (rc != SR_ERR_OK) {
ERROR("Cannot find any asymmetric keys in configuration");
return 0;
}
for (size_t i = 0; i < count; ++i) {
sr_val_t *entry = &list[i];
if (!srx_isset(session, "%s/cleartext-private-key", entry->xpath) && !srx_isset(session, "%s/public-key", entry->xpath)) {
char *private_key_format, *public_key_format;
public_key_format = srx_get_str(session, "%s/public-key-format", entry->xpath);
if (!public_key_format)
continue;
private_key_format = srx_get_str(session, "%s/private-key-format", entry->xpath);
if (!private_key_format) {
free(public_key_format);
continue;
}
if (!strcmp(private_key_format, "infix-crypto-types:rsa-private-key-format") &&
!strcmp(public_key_format, "infix-crypto-types:ssh-public-key-format")) {
char *pub_key = NULL, *priv_key = NULL, *name;
name = srx_get_str(session, "%s/name", entry->xpath);
NOTE("SSH key (%s) does not exist, generating...", name);
if (systemf("/usr/libexec/infix/mkkeys %s %s", SSH_PRIVATE_KEY, SSH_PUBLIC_KEY)) {
ERROR("Failed to generate SSH keys for %s", name);
goto next;
}
priv_key = filerd(SSH_PRIVATE_KEY, filesz(SSH_PRIVATE_KEY));
if (!priv_key)
goto next;
pub_key = filerd(SSH_PUBLIC_KEY, filesz(SSH_PUBLIC_KEY));
if (!pub_key)
goto next;
rc = srx_set_str(session, priv_key, 0, "%s/cleartext-private-key", entry->xpath);
if (rc) {
ERROR("Failed setting private key for %s... rc: %d", name, rc);
goto next;
}
rc = srx_set_str(session, pub_key, 0, "%s/public-key", entry->xpath);
if (rc != SR_ERR_OK) {
ERROR("Failed setting public key for %s... rc: %d", name, rc);
goto next;
}
next:
if (erase(SSH_PRIVATE_KEY))
ERRNO("Failed removing SSH server private key");
if (erase(SSH_PUBLIC_KEY))
ERRNO("Failed removing SSH server public key");
if (priv_key)
free(priv_key);
if (pub_key)
free(pub_key);
free(name);
}
free(public_key_format);
free(private_key_format);
}
}
if (list)
sr_free_values(list, count);
rc = keystore_update(session, config, diff);
break;
case SR_EV_CHANGE:
case SR_EV_ENABLED:
@@ -142,49 +175,35 @@ int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, str
rmrf(SSH_HOSTKEYS_NEXT);
return SR_ERR_OK;
case SR_EV_DONE:
if(fexist(SSH_HOSTKEYS_NEXT)) {
if(rmrf(SSH_HOSTKEYS)) {
if (fexist(SSH_HOSTKEYS_NEXT)) {
if (rmrf(SSH_HOSTKEYS))
ERRNO("Failed to remove old SSH hostkeys: %d", errno);
}
if (rename(SSH_HOSTKEYS_NEXT, SSH_HOSTKEYS))
ERRNO("Failed switching to new %s", SSH_HOSTKEYS);
}
return SR_ERR_OK;
default:
return SR_ERR_OK;
}
changes = lydx_get_descendant(config, "keystore", "asymmetric-keys", "asymmetric-key", NULL);
LYX_LIST_FOR_EACH(changes, change, "asymmetric-key") {
const char *name, *private_key_type, *public_key_type;
const char *private_key, *public_key;
const char *name = lydx_get_cattr(change, "name");
const char *type;
name = lydx_get_cattr(change, "name");
private_key_type = lydx_get_cattr(change, "private-key-format");
public_key_type = lydx_get_cattr(change, "public-key-format");
if (strcmp(private_key_type, "infix-crypto-types:rsa-private-key-format")) {
INFO("Private key %s is not of SSH type", name);
type = lydx_get_cattr(change, "private-key-format");
if (strcmp(type, "infix-crypto-types:rsa-private-key-format")) {
INFO("Private key %s is not of SSH type (%s)", name, type);
continue;
}
if (strcmp(public_key_type, "infix-crypto-types:ssh-public-key-format")) {
INFO("Public key %s is not of SSH type", name);
type = lydx_get_cattr(change, "public-key-format");
if (strcmp(type, "infix-crypto-types:ssh-public-key-format")) {
INFO("Public key %s is not of SSH type (%s)", name, type);
continue;
}
private_key = lydx_get_cattr(change, "cleartext-private-key");
public_key = lydx_get_cattr(change, "public-key");
if (mkdir(SSH_HOSTKEYS_NEXT, 0600) && (errno != EEXIST)) {
ERRNO("Failed creating %s", SSH_HOSTKEYS_NEXT);
rc = SR_ERR_INTERNAL;
}
if(systemf("/usr/libexec/infix/mksshkey %s %s %s %s", name, SSH_HOSTKEYS_NEXT, public_key, private_key))
rc = SR_ERR_INTERNAL;
gen_hostkey(name, change);
}
return rc;
+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))
return SR_ERR_OK;
switch (event) {
case SR_EV_DONE:
break;
+37 -33
View File
@@ -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,61 @@ 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);
cifs = lydx_get_descendant(config, "dhcp-client", "client-if", NULL);
difs = lydx_get_descendant(diff, "dhcp-client", "client-if", NULL);
/* find the modified interfaces */
LYX_LIST_FOR_EACH(difaces, diface, "interface") {
const char *ifname = lydx_get_cattr(diface, "name");
struct lyd_node *dipv4;
char *out;
/* 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");
lyd_print_mem(&out, diface, LYD_JSON,
LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
if (lydx_get_op(dif) == LYDX_OP_DELETE) {
dipv4 = lydx_get_descendant(lyd_child(diface), "ipv4", NULL);
if (!dipv4)
continue;
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);
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 +372,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;
+3 -3
View File
@@ -300,9 +300,6 @@ int infix_dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config,
int enabled = 0, added = 0, deleted = 0;
sr_error_t err = 0;
if (!lydx_get_xpathf(diff, CFG_XPATH))
return SR_ERR_OK;
switch (event) {
case SR_EV_DONE:
break;
@@ -312,6 +309,9 @@ int infix_dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config,
return SR_ERR_OK;
}
if (!lydx_get_xpathf(diff, CFG_XPATH))
return SR_ERR_OK;
global = lydx_get_descendant(config, "dhcp-server", NULL);
enabled = lydx_is_enabled(global, "enabled");
+2 -2
View File
@@ -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"
+15 -24
View File
@@ -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;
+5 -5
View File
@@ -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.
@@ -57,9 +57,7 @@ with infamy.Test() as test:
"name": tport,
"enabled": True,
"ipv4": {
"autoconf": {
"enabled": True
}
"infix-ip:autoconf": {}
}
}
]
@@ -79,8 +77,7 @@ with infamy.Test() as test:
"name": tport,
"enabled": True,
"ipv4": {
"autoconf": {
"enabled": True,
"infix-ip:autoconf": {
"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.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
}
]
}
}
})
+7 -4
View File
@@ -24,13 +24,16 @@ with infamy.Test() as test:
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))
+11 -7
View File
@@ -26,16 +26,20 @@ with infamy.Test() as test:
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))
+12 -8
View File
@@ -59,14 +59,18 @@ with infamy.Test() as test:
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"}
]
}
}
}]
}
})
+12 -8
View File
@@ -68,14 +68,18 @@ with infamy.Test() as test:
}})
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"}
]
}
}
}]
}
},
+27 -19
View File
@@ -116,15 +116,19 @@ with infamy.Test() as test:
"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 @@ with infamy.Test() as test:
"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}
]
}
}
}]
}
},
+45 -33
View File
@@ -200,17 +200,21 @@ with infamy.Test() as test:
# 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 @@ with infamy.Test() as test:
}})
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 @@ with infamy.Test() as test:
}})
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}
]
}
}
}]
}
},
@@ -212,7 +212,6 @@ table ip nat {
"enabled": True,
"forwarding": True,
"infix-ip:autoconf": {
"enabled": True,
"request-address": "169.254.1.1"
}
},