Compare commits

...
31 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
Joachim WibergandGitHub 4b3ee0fa5e Merge pull request #1222 from kernelkit/xpi-boot-time 2025-11-02 08:33:00 +01:00
Joachim Wiberg 06a4995a13 doc: prepare next release cycle in ChangeLog
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-01 23:13:19 +01:00
Joachim Wiberg 45efa9484e board/common: speed up mounting and boot
Reduce /var image size to 128M (resized at first boot anyway) and tune
mke2fs options for faster mounting.  Set ext4 'uninit_bg' feature and
use '-m 0 -i 4096' extraargs in genimage to optimize filesystem creation
and reduce overhead.  The genimage tool has several tweaks enabled by
default already, the 'uninit_bg' feature speeds up the time to check
the file system.

Disable periodic fsck with tune2fs at boot while keeping safety checks
intact.  Adjust mount options in fstab to reduce journal syncs and
improve boot time.

Fix severe performance regression in find_partition_by_label() that was
calling sgdisk on every block device including virtual devices (ram, loop,
dm-mapper). This caused boot delays of up to 24 seconds on systems with
many block devices. Now skip virtual devices that don't have GPT tables,
reducing the delay to ~2 seconds.

Also clean up is_mmc() function to use cached result.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-01 23:05:19 +01:00
Joachim Wiberg b9e53e5721 board/common: minor fixes to new boot status print
Also, these comments got lost, helps a bit understanding what's going on.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-01 23:05:18 +01:00
Joachim Wiberg 1a0dbec571 utils: add support for downloading latest bootloader
This commit adds support to simplify sdcard.img generation by downloading the
latest bootloader build for a board from the 'latest-boot' release tag.  The
tarball is saved in dl/bootloader/ and is extracted to a temporary directory
in output/build/boot-$board-xxxx on every invocation of mkimage.sh.  This is
used for invoking genimage and bmaptool before copying the resulting images
to output/images/.  (If $O is set, it is used instead of output/, above).

New options:
 -d   Download latest bootloader build for the given board
 -f   Force re-download even if bootlaoder tarball existgs

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-11-01 23:05:18 +01:00
Mattias WalströmandGitHub 151d04a2dd Merge pull request #1221 from kernelkit/silence-confd 2025-11-01 17:59:25 +01:00
Mattias Walström 10ef03c971 confd: Remove debug prints 2025-11-01 16:57:49 +01:00
Mattias WalströmandGitHub f4fb2f4f84 Merge pull request #1220 from kernelkit/nanopi-boot 2025-10-31 23:21:45 +01:00
Joachim Wiberg c3b1c28551 configs: rename rpi4_boot to rpi64_boot for consistency
Align bootloader naming with the board name raspberrypi-rpi64.

[skip ci]

Signed-off-by: Claude <noreply@anthropic.com>
2025-10-31 23:14:37 +01:00
Joachim Wiberg 97d4068f68 board: raspberrypi-rpi64: rename SD card image from rpi4 to rpi64
Align the SD card image naming with the board name for consistency.

[skip ci]

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-10-31 22:57:37 +01:00
Joachim Wiberg 38bd71614f .github: add NanoPi R2S to list of supported boot laoders
Also, sort the list alphabetically.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-10-31 22:33:41 +01:00
Mattias WalströmandGitHub 8ffb15773d Merge pull request #1219 from kernelkit/rbf
Fix board paths in bootloader defconfigs
2025-10-31 21:12:19 +01:00
Joachim Wiberg 7b26f096fa configs: fix board paths in bootloader defconfigs
Update board paths to match the restructuring in commit ab56c1be.
Fixes rpi4, cn9130_crb, and aarch64_qemu bootloader builds.

[skip ci]

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-10-31 21:09:19 +01:00
Joachim WibergandGitHub f82534d828 Merge pull request #1216 from kernelkit/coverity-fixes 2025-10-31 18:18:46 +01:00
Joachim WibergandGitHub ed2355833e Merge pull request #1209 from kernelkit/confd-refactor-callbacks
Major refactor of how sysrepo callbacks is used in confd

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-10-31 17:49:53 +01:00
Joachim Wiberg 089b160029 confd: fix possible NULL pointer deref.
Found by Coverity Scan

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-10-31 16:59:30 +01:00
Mattias Walström a280960d47 kernel-upgrade: Improve error handling 2025-10-31 09:47:37 +01:00
Mattias Walström 98b30d7d45 confd: Remove core hooks
Not needed anymore, the configuration change is sequential in change_cb.
2025-10-30 13:14:49 +01:00
Mattias Walström 5cdcf1f4fe confd: Add support for dependency tracking between modules
Sysrepo lack the functionallity for if change in model A also
should demand actions of model B. Previous we have handled this by
having callbacks for keystore changes in for example infix-services
to be able to reconfigure SSH on asymmetric key changes.

This commit instead add a pass where dependencies are found and added
to the diff.
2025-10-30 13:14:49 +01:00
Mattias Walström da29771398 confd: Refactor how sysrepo callbacks are handled
Sysrepo only care about model changes, but we want the system
configuration. Therefore add a common callback for all modules
and handle dependencies between the modules, if someone should be
run before another for example.
2025-10-30 12:28:03 +01:00
Mattias Walström 021e864a6f all.yaml: meta/bootorder.py needs to be run after ietf-system (where upgrade resides)
To verify the bootorder is still valid after that part of the suite has run.
2025-10-30 12:28:02 +01:00
Mattias Walström 9aba65e14b test: ntp: Make NTP tests more robust 2025-10-30 12:28:00 +01:00
Mattias Walström 489487be16 test: syslog: Make syslog/remote test more robust 2025-10-29 22:05:29 +01:00
67 changed files with 1552 additions and 1136 deletions
+4 -3
View File
@@ -16,11 +16,12 @@ jobs:
fail-fast: false
matrix:
defconfig:
- fireant_boot
- cn9130_crb_boot
- aarch64_qemu_boot
- rpi4_boot
- bpi_r3_boot
- cn9130_crb_boot
- fireant_boot
- nanopi_r2s_boot
- rpi64_boot
env:
MAKEFLAGS: -j5
steps:
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
run: |
case "${{ inputs.board }}" in
raspberrypi-rpi64)
echo "BOOTLOADER=rpi4_boot" >> $GITHUB_ENV
echo "BOOTLOADER=rpi64_boot" >> $GITHUB_ENV
echo "TARGET=aarch64" >> $GITHUB_ENV
;;
bananapi-bpi-r3)
@@ -25,6 +25,7 @@ jobs:
- name: Fetch kernel.org and check for 6.12 release
id: check
run: |
set -e -o pipefail
# Fetch the kernel.org frontpage and extract 6.12 version
CURRENT_VERSION=$(curl -s https://www.kernel.org/ | grep -oP '6\.12\.\d+' | head -n1)
@@ -56,6 +57,7 @@ jobs:
- name: Set up git credentials
if: steps.check.outputs.new_release == 'true'
run: |
set -e -o pipefail
git config --global user.email "ael-bot@users.noreply.github.com"
git config --global user.name "ael-bot"
@@ -68,6 +70,7 @@ jobs:
env:
GIT_TERMINAL_PROMPT: 0
run: |
set -e -o pipefail
./utils/kernel-upgrade.sh linux
- name: Create pull request
@@ -4,16 +4,23 @@ image cfg.ext4 {
size = 128M
ext4 {
label = "cfg"
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
# The /var partition will be expanded automatically at first boot
# to use the full size of the SD-card or eMMC media.
image var.ext4 {
empty = true
temporary = true
size = 1G
size = 128M
ext4 {
label = "var"
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
@@ -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
@@ -5,17 +5,24 @@ image cfg.ext4 {
ext4 {
label = "cfg"
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
# The /var partition will be expanded automatically at first boot
# to use the full size of the SD-card or eMMC media.
image var.ext4 {
empty = true
temporary = true
size = 512M
size = 128M
ext4 {
label = "var"
use-mke2fs = true
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
@@ -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
+2 -2
View File
@@ -51,9 +51,9 @@ admin@example:/>
### Pre-built images
Pre-built SD card images are available here: [infix-rpi4-sdcard.img][sdcard]
Pre-built SD card images are available here: [infix-rpi64-sdcard.img][sdcard]
[0]: https://www.raspberrypi.com/products/raspberry-pi-touch-display/
[1]: https://github.com/kernelkit/infix/releases/download/latest-boot/infix-rpi4-sdcard.img
[1]: https://github.com/kernelkit/infix/releases/download/latest-boot/infix-rpi64-sdcard.img
[2]: https://kernelkit.org/infix/latest/container/#content-mounts
[3]: https://kernelkit.org/infix/latest/scripting-restconf/
@@ -15,21 +15,28 @@ image cfg.ext4 {
ext4 {
label = "cfg"
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
# The /var partition will be expanded automatically at first boot
# to use the full size of the SD-card or eMMC media.
image var.ext4 {
empty = true
temporary = true
size = 512M
size = 128M
ext4 {
label = "var"
use-mke2fs = true
use-mke2fs = true
features = "uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
image #INFIX_ID##VERSION#-rpi4-sdcard.img {
image #INFIX_ID##VERSION#-rpi64-sdcard.img {
hdimage {
partition-table-type = "hybrid"
}
@@ -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
+2 -1
View File
@@ -11,7 +11,8 @@ image aux.ext4 {
ext4 {
label = "aux"
use-mke2fs = true
features = "^metadata_csum,^metadata_csum_seed"
features = "^metadata_csum,^metadata_csum_seed,uninit_bg"
extraargs = "-m 0 -i 4096"
}
}
+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 0 0
LABEL=var /mnt/var auto noatime,nodiratime,noauto 0 0
LABEL=cfg /mnt/cfg auto noatime,nodiratime,noauto 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
+71 -14
View File
@@ -19,6 +19,7 @@ set -e
nm=$(basename "$0")
err=0
mmc=""
opt="-k"
# External button or bootloader changed kernel command line
@@ -43,27 +44,35 @@ 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()
{
[ -n "$mmc" ] && return $mmc
# Check if primary or secondary partition (our rootfs) is on MMC
for label in primary secondary; do
devname=$(find_partition_by_label "$label" 2>/dev/null)
if [ -n "$devname" ]; then
case "$devname" in
mmcblk*)
mmc=0
return 0
;;
esac
fi
done
mmc=1
return 1
}
@@ -89,18 +98,28 @@ find_partition_by_label()
for diskpath in /sys/class/block/*; do
devname=$(basename "$diskpath")
# Skip partitions, only check whole disks
[ -f "$diskpath/partition" ] && continue
# Skip ram, loop, and other virtual devices
case "$devname" in
ram*|loop*|nullb*|dm-*) continue ;;
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;
}
}
')
@@ -109,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
}
@@ -133,7 +175,7 @@ status()
print_start()
{
printf '\r%s%s' "$(status 3)" "$*" > /dev/console
printf '\r\033[K%s%s' "$(status 3)" "$*" > /dev/console
}
print_end()
@@ -146,6 +188,12 @@ print_end()
fi
}
# Restore Finit's original progress message so its [ OK ] appears correctly
print_restore()
{
print_start "Mounting filesystems from /etc/fstab"
}
# Helper to log resize error and create failure marker (stage 1)
resize_err()
{
@@ -245,9 +293,7 @@ resize_filesystem()
mv /mnt/aux/resized.pending /mnt/aux/resized
sync
# Restore Finit's original progress message so its [ OK ] appears correctly
print_start "Mounting filesystems from /etc/fstab"
print_restore
return 0
}
@@ -256,18 +302,29 @@ 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
# 3. Already done
:
elif [ -f /mnt/aux/resized.pending ]; then
# 2. After reboot we can resize ext4
resize_filesystem "$1"
else
# 1. Start with resizing the var partition to the end of the media
resize_partition "$1"
fi
fi
# TODO: Also look for UBI partitions
# 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
+1
View File
@@ -124,6 +124,7 @@ BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
BR2_TARGET_ROOTFS_SQUASHFS=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_HOST_BMAP_TOOLS=y
BR2_PACKAGE_HOST_E2FSPROGS=y
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
BR2_PACKAGE_HOST_GENEXT2FS=y
+4
View File
@@ -100,6 +100,7 @@ BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
BR2_TARGET_ROOTFS_SQUASHFS=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_HOST_BMAP_TOOLS=y
BR2_PACKAGE_HOST_E2FSPROGS=y
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
BR2_PACKAGE_HOST_GENEXT2FS=y
@@ -114,8 +115,11 @@ INFIX_HOME="https://github.com/kernelkit/infix/"
INFIX_DOC="https://kernelkit.org/infix/"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_ALDER_ALDER=y
BR2_PACKAGE_BANANAPI_BPI_R3=y
BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y
BR2_PACKAGE_MARVELL_CN9130_CRB=y
BR2_PACKAGE_MARVELL_ESPRESSOBIN=y
BR2_PACKAGE_RASPBERRYPI_RPI64=y
BR2_PACKAGE_STYX_DCP_SC_28P=y
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
+1 -1
View File
@@ -20,7 +20,7 @@ BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2023.07.02"
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="qemu_arm64"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/extras.config $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/qemu/uboot/extras.config"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/extras.config $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/qemu-uboot/extras.config"
BR2_TARGET_UBOOT_FORMAT_DTB=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_RAUC=y
+2 -2
View File
@@ -30,9 +30,9 @@ BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2023.07.02"
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="mvebu_crb_cn9130"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/extras.config $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/cn9130-crb/uboot/extras.config"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_INFIX_PATH)/board/common/uboot/extras.config $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/marvell-cn9130-crb/uboot/extras.config"
BR2_TARGET_UBOOT_FORMAT_DTB=y
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/cn9130-crb/uboot/cn9130-crb-env.dtsi"
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/marvell-cn9130-crb/uboot/cn9130-crb-env.dtsi"
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_RAUC=y
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
+1
View File
@@ -164,6 +164,7 @@ BR2_TARGET_UBOOT_FORMAT_CUSTOM_NAME="u-boot.itb"
BR2_TARGET_UBOOT_SPL=y
BR2_TARGET_UBOOT_SPL_NAME="spl/u-boot-spl.bin.normal.out"
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="$(BR2_EXTERNAL_INFIX_PATH)/board/riscv64/visionfive2/uboot/visionfive2-env.dtsi"
BR2_PACKAGE_HOST_BMAP_TOOLS=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_RAUC=y
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
@@ -18,8 +18,8 @@ BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI=y
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI_X=y
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4=y
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI4_X=y
BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/src/board/raspberry-pi64/config.txt"
BR2_PACKAGE_RPI_FIRMWARE_CMDLINE_FILE="${BR2_EXTERNAL_INFIX_PATH}/src/board/raspberry-pi64/cmdline.txt"
BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/raspberrypi-rpi64/config.txt"
BR2_PACKAGE_RPI_FIRMWARE_CMDLINE_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/raspberrypi-rpi64/cmdline.txt"
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
# BR2_TARGET_ROOTFS_TAR is not set
BR2_TARGET_UBOOT=y
@@ -27,12 +27,12 @@ BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2025.01"
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="rpi_arm64"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/src/board/raspberry-pi64/uboot/extras.config"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/raspberrypi-rpi64/uboot/extras.config"
BR2_TARGET_UBOOT_NEEDS_DTC=y
BR2_TARGET_UBOOT_FORMAT_DTB=y
BR2_TARGET_UBOOT_FORMAT_CUSTOM=y
BR2_TARGET_UBOOT_FORMAT_CUSTOM_NAME="arch/arm/dts/infix-key.dtbo arch/arm/dts/rpi-env.dtbo"
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/src/board/raspberry-pi64/uboot/rpi-env.dtso"
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/raspberrypi-rpi64/uboot/rpi-env.dtso"
BR2_PACKAGE_HOST_BMAP_TOOLS=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_RAUC=y
+27 -1
View File
@@ -3,6 +3,31 @@ Change Log
All notable changes to the project are documented in this file.
[v25.11.0][UNRELEASED]
-------------------------
### 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
- The `utils/mkimage.sh` script now supports fetching the bootloader
- The raspberrypi-rpi64 board's bootloader is now aptly named rpi64
### Fixes
- Fix #855: User admin sometimes fails to be added to `wheel` group
- Fix serious regression in boot time, introduced in v25.10, delays the
boot step "Mounting filesystems ..." with up to 30 seconds!
[lastest-boot]: https://github.com/kernelkit/infix/releases/latest-boot
[v25.10.0][] - 2025-10-31
-------------------------
@@ -1725,7 +1750,8 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
- N/A
[buildroot]: https://buildroot.org/
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v25.09.0...HEAD
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v25.10.0...HEAD
[v25.11.0]: https://github.com/kernelkit/infix/compare/v25.10.0...v26.11.0
[v25.10.0]: https://github.com/kernelkit/infix/compare/v25.09.0...v26.10.0
[v25.09.0]: https://github.com/kernelkit/infix/compare/v25.08.0...v26.09.0
[v25.08.0]: https://github.com/kernelkit/infix/compare/v25.06.1...v26.08.0
+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
+347 -97
View File
@@ -1,21 +1,23 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#include <srx/srx_val.h>
#include <srx/common.h>
#include <srx/lyx.h>
#include "core.h"
struct confd confd;
uint32_t core_hook_prio(void)
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)
{
static uint32_t hook_prio = CB_PRIO_PASSIVE;
sr_event_t last_event = -1;
static unsigned int last_request = -1;
if (last_event == event && last_request == request_id)
return SR_ERR_OK;
last_event = event;
last_request = request_id;
return hook_prio--;
}
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)
{
/* skip in bootstrap, triggered by load script to initialize startup datastore */
if (systemf("runlevel >/dev/null 2>&1"))
return SR_ERR_OK;
@@ -26,70 +28,253 @@ int core_startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
return SR_ERR_OK;
}
static const char *ev2str(sr_event_t ev)
static confd_dependency_t add_dependencies(struct lyd_node **diff, const char *xpath, const char *value)
{
switch (ev) {
case SR_EV_UPDATE: return "UPDATE";
case SR_EV_CHANGE: return "CHANGE";
case SR_EV_DONE: return "DONE";
case SR_EV_ABORT: return "ABORT";
case SR_EV_ENABLED: return "ENABLED";
case SR_EV_RPC: return "ABORT";
default:
break;
struct lyd_node *new_node = NULL;
struct lyd_node *target = NULL;
struct lyd_node *root = NULL;
int rc;
if (!lydx_get_xpathf(*diff, "%s", xpath)) {
/* Create the path, potentially creating a new tree */
rc = lyd_new_path(NULL, LYD_CTX(*diff), xpath, value, LYD_NEW_PATH_UPDATE, &new_node);
if (rc != LY_SUCCESS || !new_node) {
ERROR("lyd_new_path failed with rc=%d", rc);
return CONFD_DEP_ERROR;
}
root = new_node;
while (root->parent)
root = lyd_parent(root);
rc = lyd_merge_siblings(diff, root, LYD_MERGE_DESTRUCT);
if (rc != LY_SUCCESS) {
ERROR("lyd_merge_siblings failed with rc=%d", rc);
lyd_free_tree(root);
return CONFD_DEP_ERROR;
}
target = lydx_get_xpathf(*diff, "%s", xpath);
if (target) {
lyd_new_meta(LYD_CTX(target), target, NULL,
"yang:operation", "replace", false, NULL);
} else {
return CONFD_DEP_ERROR;
}
return CONFD_DEP_ADDED;
}
return "UNKNOWN";
return CONFD_DEP_DONE;
}
int core_pre_hook(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 confd_dependency_t handle_dependencies(struct lyd_node **diff, struct lyd_node *config)
{
return 0;
struct lyd_node *dkeys, *dkey, *hostname;
confd_dependency_t result = CONFD_DEP_DONE;
const char *key_name;
dkeys = lydx_get_descendant(*diff, "keystore", "symmetric-keys", "symmetric-key", NULL);
LYX_LIST_FOR_EACH(dkeys, dkey, "symmetric-key") {
struct ly_set *ifaces;
uint32_t i;
key_name = lydx_get_cattr(dkey, "name");
ifaces = lydx_find_xpathf(config, "/ietf-interfaces:interfaces/interface[infix-interfaces:wifi/secret='%s']", key_name);
if (ifaces && ifaces->count > 0) {
for (i = 0; i < ifaces->count; i++) {
struct lyd_node *iface = ifaces->dnodes[i];
const char *ifname;
char xpath[256];
ifname = lydx_get_cattr(iface, "name");
snprintf(xpath, sizeof(xpath), "/ietf-interfaces:interfaces/interface[name='%s']/infix-interfaces:wifi/secret", ifname);
result = add_dependencies(diff, xpath, key_name);
if (result == CONFD_DEP_ERROR) {
ERROR("Failed to add wifi node to diff for interface %s", ifname);
ly_set_free(ifaces, NULL);
return result;
}
}
ly_set_free(ifaces, NULL);
}
}
dkeys = lydx_get_descendant(*diff, "keystore", "asymmetric-keys", "asymmetric-key", NULL);
LYX_LIST_FOR_EACH(dkeys, dkey, "asymmetric-key") {
struct ly_set *hostkeys;
uint32_t i;
key_name = lydx_get_cattr(dkey, "name");
hostkeys = lydx_find_xpathf(config, "/infix-services:ssh/hostkey[.='%s']", key_name);
if (hostkeys && hostkeys->count > 0) {
for (i = 0; i < hostkeys->count; i++) {
char xpath[256];
snprintf(xpath, sizeof(xpath), "/infix-services:ssh/hostkey[.='%s']", key_name);
result = add_dependencies(diff, xpath, key_name);
if (result == CONFD_DEP_ERROR) {
ERROR("Failed to add ssh hostkey to diff for key %s", key_name);
ly_set_free(hostkeys, NULL);
return result;
}
}
ly_set_free(hostkeys, NULL);
}
}
hostname = lydx_get_xpathf(*diff, "/ietf-system:system/hostname");
if (hostname) {
struct lyd_node *mdns, *dhcp_server;
dhcp_server = lydx_get_xpathf(config, "/infix-dhcp-server:dhcp-server/enabled");
if(dhcp_server && lydx_is_enabled(dhcp_server, "enabled")) {
result = add_dependencies(diff, "/infix-dhcp-server:dhcp-server/enabled", "true");
if (result == CONFD_DEP_ERROR) {
ERROR("Failed to add dhcp-server to diff on hostname change");
return result;
}
}
mdns = lydx_get_xpathf(config, "/infix-services:mdns");
if (mdns && lydx_is_enabled(mdns, "enabled")) {
result = add_dependencies(diff, "/infix-services:mdns/enabled", "true");
if (result == CONFD_DEP_ERROR) {
ERROR("Failed to add mdns to diff on hostname change");
return result;
}
}
}
return result;
}
/*
* Run on UPDATE to see how many modules have changes in the inbound changeset
* Run on DONE, after the last module callback has run, to activate changes.
* For details, see https://github.com/sysrepo/sysrepo/issues/2188
*/
int core_post_hook(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 change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module_name,
const char *xpath, sr_event_t event, uint32_t request_id, void *_confd)
{
static size_t num_changes = 0;
struct lyd_node *diff = NULL, *config = NULL;
static sr_event_t last_event = -1;
struct confd *confd = _confd;
static uint32_t last_request = 0;
confd_dependency_t result;
sr_data_t *cfg = NULL;
int rc = SR_ERR_OK;
int max_dep = 10;
switch (event) {
case SR_EV_CHANGE:
num_changes++;
if (request_id == last_request && last_event == event)
return SR_ERR_OK;
case SR_EV_ABORT:
num_changes = 0;
return SR_ERR_OK;
case SR_EV_DONE:
num_changes--;
if (num_changes > 0)
last_request = request_id;
last_event = event;
if (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);
return rc;
}
rc = sr_get_data(session, "//.", 0, 0, 0, &cfg);
if (rc || !cfg)
goto free_diff;
config = cfg->tree;
while ((result = handle_dependencies(&diff, config)) != CONFD_DEP_DONE) {
if (max_dep == 0) {
ERROR("Max dependency depth reached");
return SR_ERR_INTERNAL;
}
if (result == CONFD_DEP_ERROR) {
ERROR("Failed to add dependencies");
return SR_ERR_INTERNAL;
}
max_dep--;
}
#if 0
/* Debug: print diff to file */
FILE *f = fopen("/tmp/confd-diff.json", "w");
if (f) {
lyd_print_file(f, diff, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
fclose(f);
}
#endif
}
/* ietf-interfaces */
if ((rc = ietf_interfaces_change(session, config, diff, event, confd)))
goto free_diff;
/* infix-dhcp-client*/
if ((rc = infix_dhcp_client_change(session, config, diff, event, confd)))
goto free_diff;
/* ietf-keystore */
if ((rc = ietf_keystore_change(session, config, diff, event, confd)))
goto free_diff;
/* infix-services */
if ((rc = infix_services_change(session, config, diff, event, confd)))
goto free_diff;
/* ietf-syslog*/
if ((rc = ietf_syslog_change(session, config, diff, event, confd)))
goto free_diff;
/* ietf-system */
if ((rc = ietf_system_change(session, config, diff, event, confd)))
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)))
goto free_diff;
/* ietf-routing */
if ((rc = ietf_routing_change(session, config, diff, event, confd)))
goto free_diff;
/* infix-dhcp-server */
if ((rc = infix_dhcp_server_change(session, config, diff, event, confd)))
goto free_diff;
/* infix-firewall */
if ((rc = infix_firewall_change(session, config, diff, event, confd)))
goto free_diff;
if (cfg)
sr_release_data(cfg);
if (event == SR_EV_DONE) {
/* skip reload in bootstrap, implicit reload in runlevel change */
if (systemf("runlevel >/dev/null 2>&1")) {
/* trigger any tasks waiting for confd to have applied *-config */
system("initctl -nbq cond set bootstrap");
return SR_ERR_OK;
break;
default:
ERROR("core_post_hook() should not be called with event %s", ev2str(event));
return SR_ERR_SYS;
}
if (systemf("initctl -b reload")) {
EMERG("initctl reload: failed applying new configuration!");
return SR_ERR_SYS;
}
AUDIT("The new configuration has been applied.");
}
/* skip reload in bootstrap, implicit reload in runlevel change */
if (systemf("runlevel >/dev/null 2>&1")) {
/* trigger any tasks waiting for confd to have applied *-config */
system("initctl -nbq cond set bootstrap");
return SR_ERR_OK;
}
free_diff:
lyd_free_tree(diff);
return rc;
}
if (systemf("initctl -b reload")) {
EMERG("initctl reload: failed applying new configuration!");
return SR_ERR_SYS;
}
AUDIT("The new configuration has been applied.");
return SR_ERR_OK;
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_CHANGE_ALL_MODULES |
SR_SUBSCR_PASSIVE, &confd->sub);
}
int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
@@ -136,56 +321,121 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
*/
confd.ifquirks = json_load_file("/etc/product/interface-quirks.json", 0, NULL);
rc = ietf_interfaces_init(&confd);
rc = subscribe_module("ietf-interfaces", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-interfaces");
goto err;
}
rc = subscribe_module("ietf-netconf-acm", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-netconf-acm");
goto err;
}
rc = subscribe_module("infix-dhcp-client", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to infix-dhcp-client");
goto err;
}
rc = subscribe_module("ietf-keystore", &confd, SR_SUBSCR_UPDATE);
if (rc) {
ERROR("Failed to subscribe to ietf-keystore");
goto err;
}
rc = subscribe_module("infix-services", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to infix-services");
goto err;
}
rc = subscribe_module("ietf-system", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-system");
goto err;
}
rc = subscribe_module("ieee802-dot1ab-lldp", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ieee802-dot1ab-lldp");
goto err;
}
#ifdef CONTAINERS
rc = subscribe_module("infix-containers", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to infix-containers");
goto err;
}
#endif
rc = subscribe_module("infix-dhcp-server", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to infix-dhcp-server");
goto err;
}
rc = subscribe_module("ietf-routing", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-routing");
goto err;
}
rc = subscribe_module("ietf-hardware", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-hardware");
goto err;
}
rc = subscribe_module("infix-firewall", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to infix-firewall");
goto err;
}
rc = subscribe_module("infix-meta", &confd, SR_SUBSCR_UPDATE);
if (rc) {
ERROR("Failed to subscribe to infix-meta");
goto err;
}
rc = ietf_system_rpc_init(&confd);
if (rc)
goto err;
rc = ietf_keystore_init(&confd);
#ifdef CONTAINERS
rc = infix_containers_rpc_init(&confd);
if (rc)
goto err;
rc = ietf_syslog_init(&confd);
if (rc)
goto err;
rc = ietf_system_init(&confd);
if (rc)
goto err;
rc = infix_containers_init(&confd);
if (rc)
goto err;
rc = infix_dhcp_client_init(&confd);
if (rc)
goto err;
rc = infix_dhcp_server_init(&confd);
if (rc)
goto err;
rc = infix_factory_init(&confd);
if (rc)
goto err;
rc = ietf_factory_default_init(&confd);
if (rc)
goto err;
rc = ietf_routing_init(&confd);
if (rc)
goto err;
rc = infix_meta_init(&confd);
if (rc)
goto err;
rc = infix_system_sw_init(&confd);
if (rc)
goto err;
rc = infix_services_init(&confd);
if (rc)
goto err;
rc = ietf_hardware_init(&confd);
if (rc)
goto err;
rc = infix_firewall_init(&confd);
#endif
rc = infix_dhcp_server_rpc_init(&confd);
if (rc)
goto err;
rc = infix_factory_rpc_init(&confd);
if (rc)
goto err;
rc = ietf_factory_default_rpc_init(&confd);
if (rc)
goto err;
rc = infix_firewall_rpc_init(&confd);
if (rc)
goto err;
rc = infix_system_sw_rpc_init(&confd);
if (rc)
goto err;
/* Candidate infer configurations */
rc = ietf_hardware_candidate_init(&confd);
if (rc)
goto err;
rc = infix_firewall_candidate_init(&confd);
if (rc)
goto err;
rc = infix_dhcp_server_candidate_init(&confd);
if (rc)
goto err;
rc = infix_dhcp_client_candidate_init(&confd);
if (rc)
goto err;
/* YOUR_INIT GOES HERE */
return SR_ERR_OK;
err:
ERROR("init failed: %s", sr_strerror(rc));
if (confd.root)
+39 -50
View File
@@ -24,6 +24,7 @@
#include <jansson.h>
#include <srx/lyx.h>
#include <srx/common.h>
#include <srx/helpers.h>
#include <srx/systemv.h>
@@ -100,6 +101,11 @@ static inline char *xpath_base(const char *xpath)
return path;
}
typedef enum {
CONFD_DEP_DONE = 0,
CONFD_DEP_ADDED = 1,
CONFD_DEP_ERROR = 2
} confd_dependency_t;
#define REGISTER_CHANGE(s,m,x,f,c,a,u) \
if ((rc = register_change(s, m, x, f, c, a, u))) \
@@ -129,47 +135,17 @@ struct confd {
struct dagger netdag;
};
uint32_t core_hook_prio (void);
int core_pre_hook (sr_session_ctx_t *, uint32_t, const char *, const char *, sr_event_t, unsigned, void *);
int core_post_hook (sr_session_ctx_t *, uint32_t, const char *, const char *, sr_event_t, unsigned, void *);
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)
{
struct confd *ptr = (struct confd *)arg;
bool need_core_hooks;
int rc;
/*
* For standard subscribtions we hook into the callback chain
* for all modules to figure out, per changeset, which of the
* callbacks is the last one. This is where we want to call the
* global commit-done hook for candidate -> running changes and
* the startup-save hook for running -> startup copying.
*/
need_core_hooks = !(flags & SR_SUBSCR_UPDATE);
if (need_core_hooks) {
sr_module_change_subscribe(ptr->session, module, xpath, core_pre_hook, NULL,
0, SR_SUBSCR_PASSIVE, sub);
}
rc = sr_module_change_subscribe(session, module, xpath, cb, arg,
int rc = sr_module_change_subscribe(session, module, xpath, cb, arg,
CB_PRIO_PRIMARY, flags | SR_SUBSCR_DEFAULT, sub);
if (rc) {
ERROR("failed subscribing to changes of %s: %s", xpath, sr_strerror(rc));
return rc;
}
if (need_core_hooks) {
sr_module_change_subscribe(ptr->session, module, xpath, core_post_hook, NULL,
core_hook_prio(), SR_SUBSCR_PASSIVE, sub);
sr_module_change_subscribe(ptr->startup, module, xpath, core_startup_save, NULL,
core_hook_prio(), SR_SUBSCR_PASSIVE, sub);
}
return 0;
}
@@ -206,57 +182,70 @@ static inline int register_rpc(sr_session_ctx_t *session, const char *xpath,
return rc;
}
/* ietf-interfaces.c */
int ietf_interfaces_init(struct confd *confd);
int ietf_interfaces_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
int ietf_interfaces_cand_init(struct confd *confd);
/* ietf-syslog.c */
int ietf_syslog_init(struct confd *confd);
int ietf_syslog_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* ietf-system.c */
int ietf_system_init (struct confd *confd);
int ietf_system_rpc_init (struct confd *confd);
int hostnamefmt (struct confd *confd, const char *fmt, char *hostnm, size_t hostlen, char *domain, size_t domlen);
int ietf_system_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* infix-containers.c */
#ifdef CONTAINERS
int infix_containers_init(struct confd *confd);
int infix_containers_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
int infix_containers_rpc_init(struct confd *confd);
#else
static inline int infix_containers_init(struct confd *confd) { return 0; }
static inline int infix_containers_rpc_init(struct confd *confd) { return 0; }
static inline int infix_containers_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd) { return 0; }
#endif
/* infix-dhcp-common.c */
int dhcp_option_lookup(const struct lyd_node *id);
/* infix-dhcp-client.c */
int infix_dhcp_client_init(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);
int infix_dhcp_client_candidate_init(struct confd *confd);
/* infix-dhcp-server.c */
int infix_dhcp_server_init(struct confd *confd);
/* ietf-factory-default */
int ietf_factory_default_init(struct confd *confd);
int infix_dhcp_server_candidate_init(struct confd *confd);
int infix_dhcp_server_rpc_init(struct confd *confd);
int infix_dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* ietf-routing */
int ietf_routing_init(struct confd *confd);
int ietf_routing_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* infix-factory.c */
int infix_factory_init(struct confd *confd);
int infix_factory_rpc_init(struct confd *confd);
/* infix-factory.c */
int infix_meta_init(struct confd *confd);
/* ietf-factory-default */
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);
/* infix-system-software.c */
int infix_system_sw_init(struct confd *confd);
int infix_system_sw_rpc_init(struct confd *confd);
/* infix-services.c */
int infix_services_init(struct confd *confd);
int infix_services_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* ietf-hardware.c */
int ietf_hardware_init(struct confd *confd);
int ietf_hardware_candidate_init(struct confd *confd);
int ietf_hardware_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* ietf-keystore.c */
int ietf_keystore_init(struct confd *confd);
#define SSH_HOSTKEYS "/etc/ssh/hostkeys"
#define SSH_HOSTKEYS_NEXT SSH_HOSTKEYS"+"
int ietf_keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
/* infix-firewall.c */
int infix_firewall_init(struct confd *confd);
int infix_firewall_rpc_init(struct confd *confd);
int infix_firewall_candidate_init(struct confd *confd);
int infix_firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
#endif /* CONFD_CORE_H_ */
+1 -1
View File
@@ -16,7 +16,7 @@ static int factory_reset(sr_session_ctx_t *session, uint32_t sub_id, const char
return 0;
}
int ietf_factory_default_init(struct confd *confd)
int ietf_factory_default_rpc_init(struct confd *confd)
{
int rc;
+7 -23
View File
@@ -185,26 +185,15 @@ static int hardware_cand(sr_session_ctx_t *session, uint32_t sub_id, const char
return err;
}
static int change_hardware(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
int ietf_hardware_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *diff, *difs = NULL, *dif = NULL, *cifs = NULL, *cif = NULL;
sr_data_t *cfg;
struct lyd_node *difs = NULL, *dif = NULL, *cifs = NULL, *cif = NULL;
int rc = SR_ERR_OK;
struct confd *confd = (struct confd *)priv;
if (event != SR_EV_DONE)
if (event != SR_EV_DONE || !lydx_find_xpathf(diff, XPATH_BASE_))
return SR_ERR_OK;
rc = sr_get_data(session, XPATH_BASE_ "//.", 0, 0, 0, &cfg);
if (rc || !cfg)
goto err;
rc = srx_get_diff(session, &diff);
if (rc)
goto err_release_data;
cifs = lydx_get_descendant(cfg->tree, "hardware", "component", NULL);
cifs = lydx_get_descendant(config, "hardware", "component", NULL);
difs = lydx_get_descendant(diff, "hardware", "component", NULL);
LYX_LIST_FOR_EACH(difs, dif, "component") {
@@ -218,7 +207,7 @@ static int change_hardware(sr_session_ctx_t *session, uint32_t sub_id, const cha
if (op == LYDX_OP_DELETE) {
if (usb_authorize(confd->root, name, 0)) {
rc = SR_ERR_INTERNAL;
goto err_release_diff;
goto err;;
}
continue;
}
@@ -235,23 +224,18 @@ static int change_hardware(sr_session_ctx_t *session, uint32_t sub_id, const cha
admin_state = lydx_get_cattr(state, "admin-state");
if (usb_authorize(confd->root, name, !strcmp(admin_state, "unlocked"))) {
rc = SR_ERR_INTERNAL;
goto err_release_diff;
goto err;;
}
}
}
err_release_diff:
lyd_free_tree(diff);
err_release_data:
sr_release_data(cfg);
err:
return rc;
}
int ietf_hardware_init(struct confd *confd)
int ietf_hardware_candidate_init(struct confd *confd)
{
int rc = 0;
REGISTER_CHANGE(confd->session, "ietf-hardware", XPATH_BASE_, 0, change_hardware, confd, &confd->sub);
REGISTER_CHANGE(confd->cand, "ietf-hardware", XPATH_BASE_,
SR_SUBSCR_UPDATE, hardware_cand, confd, &confd->sub);
+9 -84
View File
@@ -787,12 +787,9 @@ static sr_error_t ifchange_post(sr_session_ctx_t *session, struct dagger *net,
return err ? SR_ERR_INTERNAL : SR_ERR_OK;
}
static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
int ietf_interfaces_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *diff, *cifs, *difs, *cif, *dif;
struct confd *confd = _confd;
sr_data_t *cfg;
struct lyd_node *cifs, *difs, *cif, *dif;
sr_error_t err;
switch (event) {
@@ -814,19 +811,11 @@ static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *modu
if (err)
return err;
err = sr_get_data(session, "//.", 0, 0, 0, &cfg);
if (err || !cfg)
goto err_abandon;
err = srx_get_diff(session, (struct lyd_node **)&diff);
if (err)
goto err_release_data;
cifs = lydx_get_descendant(cfg->tree, "interfaces", "interface", NULL);
cifs = lydx_get_descendant(config, "interfaces", "interface", NULL);
difs = lydx_get_descendant(diff, "interfaces", "interface", NULL);
err = netdag_init(session, &confd->netdag, cifs, difs);
if (err)
goto err_free_diff;
goto err_out;
LYX_LIST_FOR_EACH(difs, dif, "interface") {
LYX_LIST_FOR_EACH(cifs, cif, "interface")
@@ -840,71 +829,9 @@ static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *modu
}
err = err ? : ifchange_post(session, &confd->netdag, cifs, difs);
err_free_diff:
lyd_free_tree(diff);
err_release_data:
sr_release_data(cfg);
err_abandon:
if (err)
dagger_abandon(&confd->netdag);
return err;
}
static int keystorecb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
{
const struct lyd_node *diff;
const char *secret_name;
struct confd *confd = _confd;
struct lyd_node *interfaces, *interface, *dkeys, *dkey, *wifi;
sr_data_t *cfg = NULL;
int err = SR_ERR_OK;
switch (event) {
case SR_EV_CHANGE:
break;
default:
return SR_ERR_OK;
}
err = sr_get_data(session, "/interfaces/interface", 0, 0, 0, &cfg);
if (err || !cfg)
return err;
diff = sr_get_change_diff(session);
if (!diff)
goto cleanup;
interfaces = lydx_get_descendant(cfg->tree, "interfaces", "interface", NULL);
dkeys = lydx_get_descendant((struct lyd_node*) diff, "keystore", "symmetric-keys", "symmetric-key", NULL);
LYX_LIST_FOR_EACH(dkeys, dkey, "symmetric-key") {
secret_name = lydx_get_cattr(dkey, "name");
if (!secret_name)
continue;
LYX_LIST_FOR_EACH(interfaces, interface, "interface") {
const char *name;
if (iftype_from_iface(interface) != IFT_WIFI)
continue;
wifi = lydx_get_child(interface, "wifi");
if (!wifi)
continue;
name = lydx_get_cattr(wifi, "secret");
if (!name || strcmp(name, secret_name))
continue;
wifi_gen(NULL, interface, &confd->netdag);
}
}
cleanup:
if (cfg)
sr_release_data(cfg);
err_out:
return err;
}
@@ -974,18 +901,16 @@ int ietf_interfaces_get_all_l3(const struct lyd_node *tree, char ***ifaces)
return 0;
}
int ietf_interfaces_init(struct confd *confd)
int ietf_interfaces_cand_init(struct confd *confd)
{
int rc;
int rc = SR_ERR_OK;
REGISTER_CHANGE(confd->session, "ietf-interfaces", "/ietf-interfaces:interfaces//.",
SR_SUBSCR_CHANGE_ALL_MODULES, ifchange, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-keystore", "//*",
SR_SUBSCR_CHANGE_ALL_MODULES, keystorecb, confd, &confd->sub);
REGISTER_CHANGE(confd->cand, "ietf-interfaces", "/ietf-interfaces:interfaces//.",
SR_SUBSCR_UPDATE, ifchange_cand, confd, &confd->sub);
return SR_ERR_OK;
fail:
ERROR("failed, error %d: %s", rc, sr_strerror(rc));
return rc;
}
+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++;
+141 -87
View File
@@ -51,106 +51,160 @@ static char *filerd(const char *fn, size_t len)
return buf;
}
static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module_name,
const char *xpath, sr_event_t event, uint32_t request_id, void *_)
static int gen_hostkey(const char *name, struct lyd_node *change)
{
int rc = SR_ERR_INTERNAL;
sr_val_t *list = NULL;
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;
int rc = SR_ERR_OK;
if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_))
return SR_ERR_OK;
switch (event) {
case SR_EV_UPDATE:
/* Check SSH (and NETCONF) default hostkey pair */
rc = keystore_update(session, config, diff);
break;
case SR_EV_CHANGE:
case SR_EV_ENABLED:
break;
case SR_EV_ABORT:
rmrf(SSH_HOSTKEYS_NEXT);
return SR_ERR_OK;
case SR_EV_DONE:
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;
}
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;
}
changes = lydx_get_descendant(config, "keystore", "asymmetric-keys", "asymmetric-key", NULL);
LYX_LIST_FOR_EACH(changes, change, "asymmetric-key") {
const char *name = lydx_get_cattr(change, "name");
const char *type;
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);
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;
}
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;
}
gen_hostkey(name, change);
}
if (list)
sr_free_values(list, count);
return SR_ERR_OK;
}
int ietf_keystore_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, "ietf-keystore", "/ietf-keystore:keystore//.",
SR_SUBSCR_UPDATE, change_cb, confd, &confd->sub);
return SR_ERR_OK;
fail:
if(rc)
ERROR("%s failed: %s", __func__, sr_strerror(rc));
return rc;
}
+13 -34
View File
@@ -244,17 +244,18 @@ static int parse_static_routes(sr_session_ctx_t *session, struct lyd_node *paren
return num_routes;
}
static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
int ietf_routing_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
int staticd_enabled = 0, ospfd_enabled = 0, bfdd_enabled = 0;
struct lyd_node *cplane, *cplanes;
bool ospfd_running, bfdd_running;
struct lyd_node *cplane, *tmp;
bool restart_zebra = false;
int rc = SR_ERR_OK;
sr_data_t *cfg;
FILE *fp;
if (diff && !lydx_get_xpathf(diff, "/ietf-routing:routing"))
return SR_ERR_OK;
switch (event) {
case SR_EV_ENABLED: /* first time, on register. */
case SR_EV_CHANGE: /* regular change (copy cand running) */
@@ -351,27 +352,18 @@ static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t su
return SR_ERR_OK;
}
rc = sr_get_data(session, "/ietf-routing:routing/control-plane-protocols//.", 0, 0, 0, &cfg);
if (rc || !cfg) {
NOTE("No control-plane-protocols available.");
goto err_close;
}
cplanes = lydx_get_descendant(config, "routing", "control-plane-protocols", "control-plane-protocol", NULL);
LYX_LIST_FOR_EACH(cplanes, cplane, "control-plane-protocol") {
const char *type;
LY_LIST_FOR(lyd_child(cfg->tree), tmp) {
LY_LIST_FOR(lyd_child(tmp), cplane) {
const char *type;
type = lydx_get_cattr(cplane, "type");
if (!strcmp(type, "infix-routing:static")) {
staticd_enabled = parse_static_routes(session, lydx_get_child(cplane, "static-routes"), fp);
} else if (!strcmp(type, "infix-routing:ospfv2")) {
parse_ospf(session, lydx_get_child(cplane, "ospf"));
}
type = lydx_get_cattr(cplane, "type");
if (!strcmp(type, "infix-routing:static")) {
staticd_enabled = parse_static_routes(session, lydx_get_child(cplane, "static-routes"), fp);
} else if (!strcmp(type, "infix-routing:ospfv2")) {
parse_ospf(session, lydx_get_child(cplane, "ospf"));
}
}
sr_release_data(cfg);
err_close:
fclose(fp);
if (!staticd_enabled)
(void)remove(STATICD_CONF_NEXT);
@@ -379,16 +371,3 @@ err_close:
err_abandon:
return rc;
}
int ietf_routing_init(struct confd *confd)
{
int rc = 0;
REGISTER_CHANGE(confd->session, "ietf-routing", "/ietf-routing:routing/control-plane-protocols",
0, change_control_plane_protocols, confd, &confd->sub);
return SR_ERR_OK;
fail:
ERROR("Init routing failed: %s", sr_strerror(rc));
return rc;
}
+29 -41
View File
@@ -218,13 +218,12 @@ static const char *getnm(struct lyd_node *node, char *xpath, size_t len)
return name;
}
static int file_change(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 file_change(sr_session_ctx_t *session, struct lyd_node *config,struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *files, *file, *tree;
int err;
if (SR_EV_DONE != event)
if (SR_EV_DONE != event || !lydx_get_xpathf(diff, XPATH_FILE_))
return SR_ERR_OK;
err = srx_get_diff(session, &tree);
@@ -253,21 +252,15 @@ static int file_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return SR_ERR_OK;
}
static int remote_change(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 remote_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *remotes, *remote, *tree;
int err;
struct lyd_node *dremotes, *remote;
if (SR_EV_DONE != event)
if (SR_EV_DONE != event || !lydx_get_xpathf(diff, XPATH_REMOTE_))
return SR_ERR_OK;
err = srx_get_diff(session, &tree);
if (err)
return SR_ERR_OK;
remotes = lydx_get_descendant(tree, "syslog", "actions", "remote", "destination", NULL);
LYX_LIST_FOR_EACH(remotes, remote, "destination") {
dremotes = lydx_get_descendant(diff, "syslog", "actions", "remote", "destination", NULL);
LYX_LIST_FOR_EACH(dremotes, remote, "destination") {
struct lyd_node *node = lydx_get_child(remote, "name");
enum lydx_op op = lydx_get_op(node);
char path[512] = XPATH_REMOTE_;
@@ -283,23 +276,22 @@ static int remote_change(sr_session_ctx_t *session, uint32_t sub_id, const char
addr.address = srx_get_str(session, "%s/udp/address", path);
srx_get_int(session, &addr.port, SR_UINT16_T, "%s/udp/port", path);
action(session, name, xpath, &addr);
action(session, name, path, &addr);
}
}
srx_free_changes(tree);
systemf("initctl -nbq touch sysklogd");
return SR_ERR_OK;
}
static int rotate_change(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 rotate_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
char path[512] = XPATH_ROTATE_;
char *sz, *cnt;
FILE *fp;
if (SR_EV_DONE != event)
if (SR_EV_DONE != event || !lydx_get_xpathf(diff, XPATH_ROTATE_))
return SR_ERR_OK;
fp = fopen(SYSLOG_ROTATE, "w");
@@ -308,13 +300,13 @@ static int rotate_change(sr_session_ctx_t *session, uint32_t sub_id, const char
return SR_ERR_SYS;
}
sz = srx_get_str(session, "%s/max-file-size", xpath);
sz = srx_get_str(session, "%s/max-file-size", path);
if (sz) {
fprintf(fp, "rotate_size %sk\n", sz);
free(sz);
}
cnt = srx_get_str(session, "%s/number-of-files", xpath);
cnt = srx_get_str(session, "%s/number-of-files", path);
if (cnt) {
fprintf(fp, "rotate_count %s\n", cnt);
free(cnt);
@@ -326,18 +318,18 @@ static int rotate_change(sr_session_ctx_t *session, uint32_t sub_id, const char
return SR_ERR_OK;
}
static int server_change(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 server_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
char path[512] = XPATH_SERVER_;
sr_val_t *list = NULL;
size_t count;
FILE *fp;
if (SR_EV_DONE != event)
if (SR_EV_DONE != event || !lydx_get_xpathf(diff, XPATH_SERVER_))
return SR_ERR_OK;
if (!srx_enabled(session, "%s/enabled", xpath)) {
if (remove(SYSLOG_SERVER))
if (!srx_enabled(session, "%s/enabled", path)) {
if (erase(SYSLOG_SERVER))
ERRNO("failed disabling syslog server");
goto done;
}
@@ -351,7 +343,7 @@ static int server_change(sr_session_ctx_t *session, uint32_t sub_id, const char
/* Allow listening on port 514, or custom listen below */
fprintf(fp, "secure_mode 0\n");
if (!srx_get_items(session, &list, &count, "%s/listen/udp", xpath)) {
if (!srx_get_items(session, &list, &count, "%s/listen/udp", path)) {
for (size_t i = 0; i < count; ++i) {
sr_val_t *entry = &list[i];
char *address, *port;
@@ -373,21 +365,17 @@ done:
return SR_ERR_OK;
}
int ietf_syslog_init(struct confd *confd)
int ietf_syslog_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
int rc = SR_ERR_SYS;
if (!confd)
goto fail;
REGISTER_CHANGE(confd->session, "ietf-syslog", XPATH_FILE_"//.", 0, file_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-syslog", XPATH_REMOTE_"//.", 0, remote_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-syslog", XPATH_ROTATE_"//.", 0, rotate_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-syslog", XPATH_SERVER_"//.", 0, server_change, confd, &confd->sub);
int rc = SR_ERR_OK;
if ((rc = file_change(session, config, diff, event, confd)))
return rc;
if ((rc = remote_change(session, config, diff, event, confd)))
return rc;
if ((rc = rotate_change(session, config, diff, event, confd)))
return rc;
if ((rc = server_change(session, config, diff, event, confd)))
return rc;
return SR_ERR_OK;
fail:
ERROR("%s failed: %s", __func__, sr_strerror(rc));
return rc;
}
+73 -55
View File
@@ -21,12 +21,18 @@
#include "base64.h"
#include "core.h"
#define NACM_BASE_ "/ietf-netconf-acm:nacm"
#define XPATH_BASE_ "/ietf-system:system"
#define XPATH_AUTH_ XPATH_BASE_"/authentication"
#define CLOCK_PATH_ "/ietf-system:system-state/clock"
#define PLATFORM_PATH_ "/ietf-system:system-state/platform"
#define PASSWORD_PATH "/ietf-system:system/authentication/user/password"
#define NACM_BASE_ "/ietf-netconf-acm:nacm"
#define XPATH_BASE_ "/ietf-system:system"
#define XPATH_AUTH_ XPATH_BASE_"/authentication"
#define XPATH_NTP_ XPATH_BASE_"/ntp"
#define XPATH_DNS_ XPATH_BASE_"/dns-resolver"
#define XPATH_HOSTNAME_ XPATH_BASE_"/hostname"
#define XPATH_MOTD_BANNER_ XPATH_BASE_"/infix-system:motd-banner"
#define XPATH_MOTD_ XPATH_BASE_"/infix-system:motd"
#define XPATH_EDITOR_ XPATH_BASE_"/infix-system:text-editor"
#define CLOCK_PATH_ "/ietf-system:system-state/clock"
#define PLATFORM_PATH_ "/ietf-system:system-state/platform"
#define PASSWORD_PATH "/ietf-system:system/authentication/user/password"
#define _PATH_PASSWD "/etc/passwd"
#define _PATH_HOSTNAME "/etc/hostname"
@@ -210,12 +216,13 @@ static int sys_reload_services(void)
#define TIMEZONE_PREV TIMEZONE_CONF "-"
#define TIMEZONE_NEXT TIMEZONE_CONF "+"
static int change_clock(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 change_clock(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
char *tz_utc_offset, *timezone;
int rc = SR_ERR_OK;
if (diff && !lydx_get_xpathf(diff, XPATH_BASE_"/clock"))
return SR_ERR_OK;
switch (event) {
case SR_EV_ENABLED: /* first time, on register. */
case SR_EV_CHANGE: /* regular change (copy cand running) */
@@ -280,8 +287,7 @@ err:
return rc;
}
static int change_ntp(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *_, sr_event_t event, unsigned request_id, void *priv)
static int change_ntp(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
sr_change_iter_t *iter = NULL;
int rc, err = SR_ERR_OK;
@@ -289,6 +295,8 @@ static int change_ntp(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
sr_val_t *val;
size_t cnt;
if (diff && !lydx_get_xpathf(diff, XPATH_NTP_))
return SR_ERR_OK;
switch (event) {
case SR_EV_ENABLED: /* first time, on register. */
case SR_EV_CHANGE: /* regular change (copy cand running) */
@@ -299,7 +307,7 @@ static int change_ntp(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
return SR_ERR_OK;
case SR_EV_DONE:
if (!srx_enabled(session, XPATH_BASE_"/ntp/enabled")) {
if (!srx_enabled(session, XPATH_NTP_"/enabled")) {
systemf("rm -rf /etc/chrony/conf.d/* /etc/chrony/sources.d/*");
systemf("initctl -nbq disable chronyd");
return SR_ERR_OK;
@@ -411,8 +419,7 @@ static int change_ntp(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
#define RESOLV_PREV RESOLV_CONF "-"
#define RESOLV_NEXT RESOLV_CONF "+"
static int change_dns(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 change_dns(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
const char *fn = RESOLV_NEXT;
int timeout = 0, attempts = 0;
@@ -421,6 +428,9 @@ static int change_dns(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
size_t cnt;
FILE *fp;
if (diff && !lydx_get_xpathf(diff, XPATH_DNS_))
return SR_ERR_OK;
switch (event) {
case SR_EV_ENABLED: /* first time, on register. */
case SR_EV_CHANGE: /* regular change (copy cand running) */
@@ -453,8 +463,8 @@ static int change_dns(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
return SR_ERR_SYS;
}
SRX_GET_UINT8(session, timeout, XPATH_BASE_"/dns-resolver/options/timeout");
SRX_GET_UINT8(session, attempts, XPATH_BASE_"/dns-resolver/options/attempts");
SRX_GET_UINT8(session, timeout, XPATH_DNS_"/options/timeout");
SRX_GET_UINT8(session, attempts, XPATH_DNS_"/dns-resolver/options/attempts");
if (timeout || attempts) {
fprintf(fp, "options");
if (timeout)
@@ -1288,11 +1298,10 @@ cleanup:
return err;
}
static int change_auth(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 change_auth(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct confd *confd = (struct confd *)priv;
if (diff && !lydx_get_xpathf(diff, XPATH_AUTH_))
return SR_ERR_OK;
switch (event) {
case SR_EV_UPDATE:
return change_auth_ctp(confd, session);
@@ -1307,14 +1316,13 @@ static int change_auth(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return SR_ERR_OK;
}
static int change_nacm(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *_, sr_event_t event, unsigned request_id, void *priv)
static int change_nacm(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
sr_val_t *users = NULL;
size_t user_count = 0;
int rc;
if (event != SR_EV_DONE)
if (event != SR_EV_DONE ||!lydx_get_xpathf(diff, NACM_BASE_))
return SR_ERR_OK;
/* Fetch all users from ietf-system */
@@ -1346,18 +1354,18 @@ cleanup:
return 0;
}
static int change_motd(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 change_motd(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
const char *fn = "/etc/motd";
char *message;
int rc = 0;
/* Ignore all events except SR_EV_DONE */
if (event != SR_EV_DONE)
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_MOTD_))
return SR_ERR_OK;
message = srx_get_str(session, "%s", xpath);
message = srx_get_str(session, "%s", XPATH_MOTD_);
if (message) {
rc = writesf(message, "w", "%s", fn);
free(message);
@@ -1371,8 +1379,7 @@ static int change_motd(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return SR_ERR_OK;
}
static int change_motd_banner(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 change_motd_banner(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
const char *fn = "/etc/motd";
unsigned char *raw;
@@ -1380,24 +1387,24 @@ static int change_motd_banner(sr_session_ctx_t *session, uint32_t sub_id, const
int rc = 0;
/* Ignore all events except SR_EV_DONE */
if (event != SR_EV_DONE)
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_MOTD_BANNER_))
return SR_ERR_OK;
legacy = srx_get_str(session, "/ietf-system:system/infix-system:motd");
legacy = srx_get_str(session, XPATH_MOTD_);
if (legacy) {
NOTE("Legacy /system/motd exists, skipping %s", xpath);
NOTE("Legacy /system/motd exists, skipping %s", XPATH_MOTD_BANNER_);
free(legacy);
return SR_ERR_OK;
}
raw = (unsigned char *)srx_get_str(session, "%s", xpath);
raw = (unsigned char *)srx_get_str(session, "%s", XPATH_BASE_"/infix-system:motd-banner");
if (raw) {
unsigned char *txt;
size_t txt_len;
txt = base64_decode(raw, strlen((char *)raw), &txt_len);
if (!txt) {
ERRNO("failed base64 decoding of %s", xpath);
ERRNO("failed base64 decoding of %s", XPATH_BASE_"/infix-system:motd-banner");
rc = -1;
} else {
FILE *fp = fopen(fn, "w");
@@ -1431,8 +1438,7 @@ static int change_motd_banner(sr_session_ctx_t *session, uint32_t sub_id, const
return SR_ERR_OK;
}
static int change_editor(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 change_editor(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
const char *alt = "/etc/alternatives/editor";
struct { const char *editor, *path; } map[] = {
@@ -1444,10 +1450,10 @@ static int change_editor(sr_session_ctx_t *session, uint32_t sub_id, const char
int rc = 0;
/* Ignore all events except SR_EV_DONE */
if (event != SR_EV_DONE)
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_EDITOR_))
return SR_ERR_OK;
editor = srx_get_str(session, "%s", xpath);
editor = srx_get_str(session, "%s", XPATH_BASE_"/infix-system:text-editor");
if (!editor)
return SR_ERR_OK;
@@ -1550,20 +1556,18 @@ int hostnamefmt(struct confd *confd, const char *fmt, char *hostnm, size_t hostl
return 0;
}
static int change_hostname(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 change_hostname(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct confd *confd = (struct confd *)priv;
const char *hostip = "127.0.1.1";
char hostnm[65], domain[65];
char buf[256], *fmt;
FILE *nfp, *fp;
int err, fd;
if (event != SR_EV_DONE)
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, XPATH_HOSTNAME_))
return SR_ERR_OK;
fmt = srx_get_str(session, "%s", xpath);
fmt = srx_get_str(session, "%s", XPATH_BASE_"/hostname");
if (!fmt)
fmt = strdup(nm);
@@ -1648,24 +1652,38 @@ err:
return SR_ERR_OK;
}
int ietf_system_init(struct confd *confd)
int ietf_system_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
int rc = SR_ERR_OK;
if ((rc = change_auth(session, config, diff, event, confd)))
return rc;
if ((rc = change_ntp(session, config, diff, event, confd)))
return rc;
if ((rc = change_dns(session, config, diff, event, confd)))
return rc;
if ((rc = change_editor(session,config, diff, event, confd)))
return rc;
if ((rc = change_clock(session, config, diff, event, confd)))
return rc;
if ((rc = change_hostname(session, config, diff, event, confd)))
return rc;
if ((rc = change_motd(session, config, diff, event, confd)))
return rc;
if ((rc = change_motd_banner(session, config, diff, event, confd)))
return rc;
if ((rc = change_nacm(session, config, diff, event, confd))) /* Must be called after ietf_system_change_auth, which create the users */
return rc;
return SR_ERR_OK;
}
int ietf_system_rpc_init(struct confd *confd)
{
int rc;
os_init();
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_AUTH_, 0, change_auth, confd, &confd->sub);
REGISTER_MONITOR(confd->session, "ietf-netconf-acm", "/ietf-netconf-acm:nacm//.",
0, change_nacm, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/hostname", 0, change_hostname, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/infix-system:motd", 0, change_motd, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/infix-system:motd-banner", 0, change_motd_banner, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/infix-system:text-editor", 0, change_editor, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/clock", 0, change_clock, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/ntp", 0, change_ntp, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ietf-system", XPATH_BASE_"/dns-resolver", 0, change_dns, confd, &confd->sub);
REGISTER_RPC(confd->session, "/ietf-system:system-restart", rpc_exec, "reboot", &confd->sub);
REGISTER_RPC(confd->session, "/ietf-system:system-shutdown", rpc_exec, "poweroff", &confd->sub);
REGISTER_RPC(confd->session, "/ietf-system:set-current-datetime", rpc_set_datetime, NULL, &confd->sub);
+8 -28
View File
@@ -349,23 +349,20 @@ static int del(const char *name)
return SR_ERR_OK;
}
static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
int infix_containers_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *diff, *cifs, *difs, *cif, *dif;
struct lyd_node *cifs, *difs, *cif, *dif;
sr_error_t err = 0;
sr_data_t *cfg;
if (diff && !lydx_get_xpathf(diff, CFG_XPATH))
return SR_ERR_OK;
switch (event) {
case SR_EV_DONE:
break;
case SR_EV_CHANGE:
err = sr_get_data(session, CFG_XPATH "//.", 0, 0, 0, &cfg);
if (err || !cfg)
return SR_ERR_INTERNAL;
cifs = lydx_get_descendant(cfg->tree, "containers", "container", NULL);
cifs = lydx_get_descendant(config, "containers", "container", NULL);
LYX_LIST_FOR_EACH(cifs, cif, "container") {
struct lyd_node *mount;
LYX_LIST_FOR_EACH(lyd_child(cif), mount, "mount") {
@@ -379,13 +376,10 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
"Container '%s': mount '%s' source file '%s' is invalid: %s",
lydx_get_cattr(cif, "name"), id, src, reason);
sr_session_set_error_message(session, errmsg);
sr_release_data(cfg);
return SR_ERR_VALIDATION_FAILED;
}
}
}
sr_release_data(cfg);
return SR_ERR_OK;
case SR_EV_ABORT:
@@ -393,15 +387,7 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
return SR_ERR_OK;
}
err = sr_get_data(session, CFG_XPATH "//.", 0, 0, 0, &cfg);
if (err || !cfg)
goto err_abandon;
err = srx_get_diff(session, &diff);
if (err)
goto err_release_data;
cifs = lydx_get_descendant(cfg->tree, "containers", "container", NULL);
cifs = lydx_get_descendant(config, "containers", "container", NULL);
difs = lydx_get_descendant(diff, "containers", "container", NULL);
/* find the modified one, delete or recreate only that */
@@ -422,11 +408,6 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
}
}
lyd_free_tree(diff);
err_release_data:
sr_release_data(cfg);
err_abandon:
return err;
}
@@ -484,11 +465,10 @@ static int oci_load(sr_session_ctx_t *session, uint32_t sub_id, const char *xpat
return SR_ERR_OK;
}
int infix_containers_init(struct confd *confd)
int infix_containers_rpc_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, MODULE, CFG_XPATH, 0, change, confd, &confd->sub);
REGISTER_RPC(confd->session, CFG_XPATH "/container/start", action, NULL, &confd->sub);
REGISTER_RPC(confd->session, CFG_XPATH "/container/stop", action, NULL, &confd->sub);
REGISTER_RPC(confd->session, CFG_XPATH "/container/restart", action, NULL, &confd->sub);
+36 -48
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,72 +278,61 @@ static void del(const char *ifname)
systemf("initctl -bfq delete dhcp-client-%s", ifname);
}
static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_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, *diff, *cifs, *difs, *cif, *dif;
struct lyd_node *ifaces, *difaces, *iface, *diface, *ipv4, *dhcp, *ddhcp;
sr_error_t err = 0;
sr_data_t *cfg;
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;
}
err = sr_get_data(session, "//.", 0, 0, 0, &cfg);
if (err || !cfg)
goto err_abandon;
ifaces = lydx_get_descendant(config, "interfaces", "interface", NULL);
difaces = lydx_get_descendant(diff, "interfaces", "interface", NULL);
err = srx_get_diff(session, &diff);
if (err)
goto err_release_data;
/* 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;
global = lydx_get_descendant(cfg->tree, "dhcp-client", NULL);
ena = lydx_is_enabled(global, "enabled");
lyd_print_mem(&out, diface, LYD_JSON,
LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL);
cifs = lydx_get_descendant(cfg->tree, "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);
}
}
lyd_free_tree(diff);
err_release_data:
sr_release_data(cfg);
err_abandon:
return err;
}
@@ -383,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;
@@ -421,11 +410,10 @@ static int cand(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
return SR_ERR_OK;
}
int infix_dhcp_client_init(struct confd *confd)
int infix_dhcp_client_candidate_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, MODULE, XPATH, 0, change, confd, &confd->sub);
REGISTER_CHANGE(confd->cand, MODULE, XPATH"//.", SR_SUBSCR_UPDATE, cand, confd, &confd->sub);
return SR_ERR_OK;
+19 -21
View File
@@ -294,13 +294,11 @@ static void del(const char *subnet, struct lyd_node *cfg)
ERRNO("Failed switching to new %s", DNSMASQ_LEASES);
}
static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
int infix_dhcp_server_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, *diff, *cifs, *difs, *cif, *dif;
struct lyd_node *global, *cifs, *difs, *cif, *dif;
int enabled = 0, added = 0, deleted = 0;
sr_error_t err = 0;
sr_data_t *cfg;
switch (event) {
case SR_EV_DONE:
@@ -311,18 +309,13 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
return SR_ERR_OK;
}
err = sr_get_data(session, "//.", 0, 0, 0, &cfg);
if (err || !cfg)
goto err_abandon;
if (!lydx_get_xpathf(diff, CFG_XPATH))
return SR_ERR_OK;
err = srx_get_diff(session, &diff);
if (err)
goto err_release_data;
global = lydx_get_descendant(cfg->tree, "dhcp-server", NULL);
global = lydx_get_descendant(config, "dhcp-server", NULL);
enabled = lydx_is_enabled(global, "enabled");
cifs = lydx_get_descendant(cfg->tree, "dhcp-server", "subnet", NULL);
cifs = lydx_get_descendant(config, "dhcp-server", "subnet", NULL);
difs = lydx_get_descendant(diff, "dhcp-server", "subnet", NULL);
/* find the modified one, delete or recreate only that */
@@ -356,7 +349,7 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
if (!fp)
goto err_done;
node = lydx_get_xpathf(cfg->tree, "/ietf-system:system/hostname");
node = lydx_get_xpathf(config, "/ietf-system:system/hostname");
if (node) {
const char *hostname = lyd_get_value(node);
const char *ptr = hostname ? strchr(hostname, '.') : NULL;
@@ -385,11 +378,6 @@ err_done:
if (added || deleted)
system("initctl -nbq touch dnsmasq");
lyd_free_tree(diff);
err_release_data:
sr_release_data(cfg);
err_abandon:
return err;
}
@@ -461,12 +449,22 @@ static int clear_stats(sr_session_ctx_t *session, uint32_t sub_id, const char *x
return SR_ERR_OK;
}
int infix_dhcp_server_init(struct confd *confd)
int infix_dhcp_server_candidate_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, MODULE, CFG_XPATH, 0, change, confd, &confd->sub);
REGISTER_CHANGE(confd->cand, MODULE, CFG_XPATH "//.", SR_SUBSCR_UPDATE, cand, confd, &confd->sub);
return SR_ERR_OK;
fail:
ERROR("init failed: %s", sr_strerror(rc));
return rc;
}
int infix_dhcp_server_rpc_init(struct confd *confd)
{
int rc;
REGISTER_RPC(confd->session, CFG_XPATH "/statistics/clear", clear_stats, NULL, &confd->sub);
return SR_ERR_OK;
+1 -1
View File
@@ -33,7 +33,7 @@ static int rpc(sr_session_ctx_t *session, uint32_t sub_id, const char *xpath,
return rc;
}
int infix_factory_init(struct confd *confd)
int infix_factory_rpc_init(struct confd *confd)
{
int rc;
REGISTER_RPC(confd->session, "/infix-factory-default:factory-default", rpc, NULL, &confd->fsub);
+23 -26
View File
@@ -68,6 +68,9 @@ static void mark_interfaces_used(struct lyd_node *cfg, char **ifaces)
{
struct lyd_node *node;
if (!ifaces)
return;
LYX_LIST_FOR_EACH(lyd_child(cfg), node, "interface") {
const char *ifname = lyd_get_value(node);
@@ -477,16 +480,16 @@ static int infer_policy(sr_session_ctx_t *session, const char *name, const char
}
#endif
static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
int infix_firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *tree, *global;
struct lyd_node *clist, *cnode;
struct lyd_node *diff = NULL;
sr_error_t err = SR_ERR_OK;
sr_data_t *cfg = NULL;
char **ifaces = NULL;
if (diff && !lydx_get_xpathf(diff, XPATH))
return SR_ERR_OK;
switch (event) {
case SR_EV_CHANGE:
/* Generate configuration to /etc/firewalld+ */
@@ -518,11 +521,7 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
return SR_ERR_OK;
}
err = sr_get_data(session, "//.", 0, 0, 0, &cfg);
if (err || !cfg)
return SR_ERR_INTERNAL;
tree = cfg->tree;
tree = config;
global = lydx_get_descendant(tree, "firewall", NULL);
/* Clean up any stale /etc/firewalld+ first */
@@ -540,13 +539,6 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
ifaces = NULL;
}
err = srx_get_diff(session, &diff);
if (err)
goto done;
if (!diff)
goto done;
/* Create /etc/firewalld+ directory structure */
if (fmkpath(0755, FIREWALLD_DIR_NEXT) ||
fmkpath(0755, FIREWALLD_ZONES_DIR) ||
@@ -642,12 +634,6 @@ done:
free(ifaces);
}
if (diff)
lyd_free_tree(diff);
if (cfg)
sr_release_data(cfg);
return err;
}
@@ -699,7 +685,7 @@ static int cand(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
#if INFER_POLICY
/* Infer allow-host-ipv6 policy */
rc = infer_policy(session, "allow-host-ipv6",
rc = infer_policy(session, "allow-host-ipv6",
"Allows basic IPv6 functionality for the host.",
"continue", any, host, icmp_types);
if (rc)
@@ -725,12 +711,10 @@ static int lockdown(sr_session_ctx_t *session, uint32_t sub_id, const char *xpat
return SR_ERR_OK;
}
int infix_firewall_init(struct confd *confd)
int infix_firewall_rpc_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, MODULE, XPATH "//.", 0, change, confd, &confd->sub);
REGISTER_CHANGE(confd->cand, MODULE, XPATH "//.", SR_SUBSCR_UPDATE, cand, confd, &confd->sub);
REGISTER_RPC(confd->session, XPATH "/lockdown-mode", lockdown, NULL, &confd->sub);
return SR_ERR_OK;
@@ -738,3 +722,16 @@ fail:
ERROR("init failed: %s", sr_strerror(rc));
return rc;
}
int infix_firewall_candidate_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->cand, MODULE, XPATH "//.", SR_SUBSCR_UPDATE, cand, confd, &confd->sub);
return SR_ERR_OK;
fail:
ERROR("init failed: %s", sr_strerror(rc));
return rc;
}
+1 -14
View File
@@ -18,23 +18,10 @@ static int set_version(sr_session_ctx_t *session)
return SR_ERR_OK;
}
static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
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)
{
if (event == SR_EV_UPDATE)
return set_version(session);
return SR_ERR_OK;
}
int infix_meta_init(struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, "infix-meta", META_XPATH, SR_SUBSCR_UPDATE,
change_cb, confd, &confd->sub);
return SR_ERR_OK;
fail:
ERROR("%s(): failed. %s", __func__, sr_strerror(rc));
return rc;
}
+71 -142
View File
@@ -19,9 +19,6 @@
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
#define SSH_HOSTKEYS "/etc/ssh/hostkeys"
#define SSH_HOSTKEYS_NEXT SSH_HOSTKEYS"+"
#define LLDP_CONFIG "/etc/lldpd.d/confd.conf"
#define LLDP_CONFIG_NEXT LLDP_CONFIG"+"
@@ -39,7 +36,13 @@
#define SSHD_CONFIG_BASE SSH_BASE "/sshd_config.d"
#define SSHD_CONFIG_LISTEN SSHD_CONFIG_BASE "/listen.conf"
#define SSHD_CONFIG_HOSTKEY SSHD_CONFIG_BASE "/host-keys.conf"
#define LLDP_XPATH "/ieee802-dot1ab-lldp:lldp"
#define SSH_XPATH "/infix-services:ssh"
#define MDNS_XPATH "/infix-services:mdns"
#define WEB_XPATH "/infix-services:web"
#define WEB_RESTCONF_XPATH WEB_XPATH"/restconf"
#define WEB_NETBROWSE_XPATH WEB_XPATH"/netbrowse"
#define WEB_CONSOLE_XPATH WEB_XPATH"/console"
typedef enum {
FOREACH_SVC(GENERATE_ENUM)
} svc;
@@ -185,12 +188,6 @@ static void svc_enadis(int ena, svc type, const char *svc)
systemf("initctl -nbq touch nginx");
}
static int hostname_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
{
return mdns_records("update", all);
}
static void fput_list(FILE *fp, struct lyd_node *cfg, const char *list, const char *heading)
{
const char *prefix = heading;
@@ -279,14 +276,16 @@ static void mdns_cname(sr_session_ctx_t *session)
svc_enadis(ena, none, "mdns-alias");
}
static int mdns_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int mdns_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *srv = NULL;
sr_data_t *cfg;
int ena;
cfg = get(session, event, xpath, &srv, "mdns", NULL);
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, MDNS_XPATH))
return SR_ERR_OK;
cfg = get(session, event, MDNS_XPATH, &srv, "mdns", NULL);
if (!cfg)
return SR_ERR_OK;
@@ -305,20 +304,18 @@ static int mdns_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return put(cfg);
}
static int lldp_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int lldp_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *node = NULL;
sr_data_t *cfg;
struct lyd_node *subnode;
if (diff && !lydx_get_xpathf(diff, LLDP_XPATH))
return SR_ERR_OK;
switch (event) {
case SR_EV_ENABLED:
case SR_EV_CHANGE:
if (sr_get_data(session, xpath, 0, 0, 0, &cfg) || !cfg)
break;
node = cfg->tree;
node = lydx_get_xpathf(config, LLDP_XPATH);
if (lydx_is_enabled(node, "enabled")){
const char *tx_interval = lydx_get_cattr(node, "message-tx-interval");
FILE *fp = fopen(LLDP_CONFIG_NEXT, "w");
@@ -342,7 +339,7 @@ static int lldp_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
fclose(fp);
}
return put(cfg);
return SR_ERR_OK;
case SR_EV_DONE:
if (fexist(LLDP_CONFIG_NEXT)){
@@ -356,7 +353,7 @@ static int lldp_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
if (erase(LLDP_CONFIG))
ERRNO("Failed to remove old %s", LLDP_CONFIG);
svc_change(session, event, xpath, "lldp", "lldpd");
svc_change(session, event, LLDP_XPATH, "lldp", "lldpd");
break;
case SR_EV_ABORT:
@@ -370,13 +367,15 @@ static int lldp_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return SR_ERR_OK;
}
static int ttyd_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int ttyd_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *srv = NULL;
sr_data_t *cfg;
cfg = get(session, event, xpath, &srv, "web", "console", NULL);
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, WEB_CONSOLE_XPATH))
return SR_ERR_OK;
cfg = get(session, event, WEB_XPATH, &srv, "web", "console", NULL);
if (!cfg)
return SR_ERR_OK;
@@ -385,13 +384,15 @@ static int ttyd_change(sr_session_ctx_t *session, uint32_t sub_id, const char *m
return put(cfg);
}
static int netbrowse_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int netbrowse_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *srv = NULL;
sr_data_t *cfg;
cfg = get(session, event, xpath, &srv, "web", "netbrowse", NULL);
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, WEB_NETBROWSE_XPATH))
return SR_ERR_OK;
cfg = get(session, event, WEB_XPATH, &srv, "web", "netbrowse", NULL);
if (!cfg)
return SR_ERR_OK;
@@ -401,13 +402,15 @@ static int netbrowse_change(sr_session_ctx_t *session, uint32_t sub_id, const ch
return put(cfg);
}
static int restconf_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int restconf_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *srv = NULL;
sr_data_t *cfg;
cfg = get(session, event, xpath, &srv, "web", "restconf", NULL);
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, WEB_RESTCONF_XPATH))
return SR_ERR_OK;
cfg = get(session, event, WEB_XPATH, &srv, "web", "restconf", NULL);
if (!cfg)
return SR_ERR_OK;
@@ -416,17 +419,18 @@ static int restconf_change(sr_session_ctx_t *session, uint32_t sub_id, const cha
return put(cfg);
}
static int ssh_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int ssh_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *ssh = NULL, *listen, *host_key;
sr_error_t rc = SR_ERR_OK;
sr_data_t *cfg;
FILE *fp;
if (diff && !lydx_get_xpathf(diff, SSH_XPATH))
return SR_ERR_OK;
switch (event) {
case SR_EV_DONE:
return svc_change(session, event, xpath, "ssh", "sshd");
return svc_change(session, event, SSH_XPATH, "ssh", "sshd");
case SR_EV_ENABLED:
case SR_EV_CHANGE:
break;
@@ -436,10 +440,7 @@ static int ssh_change(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
return SR_ERR_OK;
}
if (sr_get_data(session, xpath, 0, 0, 0, &cfg) || !cfg) {
return SR_ERR_OK;
}
ssh = cfg->tree;
ssh = lydx_get_xpathf(config, SSH_XPATH);
if (!lydx_is_enabled(ssh, "enabled")) {
goto out;
@@ -479,27 +480,29 @@ static int ssh_change(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
fclose(fp);
out:
sr_release_data(cfg);
return rc;
}
static int web_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
static int web_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
struct lyd_node *srv = NULL;
sr_data_t *cfg;
int ena;
cfg = get(session, event, xpath, &srv, "web", NULL);
if (event != SR_EV_DONE || !lydx_get_xpathf(diff, WEB_XPATH))
return SR_ERR_OK;
cfg = get(session, event, WEB_XPATH, &srv, "web", NULL);
if (!cfg)
return SR_ERR_OK;
ena = lydx_is_enabled(srv, "enabled");
if (ena) {
svc_enadis(srx_enabled(session, "%s/console/enabled", xpath), ttyd, "ttyd");
svc_enadis(srx_enabled(session, "%s/netbrowse/enabled", xpath), netbrowse, "netbrowse");
svc_enadis(srx_enabled(session, "%s/restconf/enabled", xpath), restconf, "restconf");
svc_enadis(srx_enabled(session, "%s/enabled", WEB_CONSOLE_XPATH), ttyd, "ttyd");
svc_enadis(srx_enabled(session, "%s/enabled", WEB_NETBROWSE_XPATH), netbrowse, "netbrowse");
svc_enadis(srx_enabled(session, "%s/enabled", WEB_RESTCONF_XPATH), restconf, "restconf");
} else {
svc_enadis(0, ttyd, NULL);
svc_enadis(0, netbrowse, NULL);
@@ -512,104 +515,30 @@ static int web_change(sr_session_ctx_t *session, uint32_t sub_id, const char *mo
return put(cfg);
}
/* Store SSH public/private keys */
static int change_keystore_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module_name,
const char *xpath, sr_event_t event, uint32_t request_id, void *_)
{
int rc = SR_ERR_OK;
sr_data_t *cfg;
struct lyd_node *changes, *change;
switch (event) {
case SR_EV_CHANGE:
case SR_EV_ENABLED:
break;
case SR_EV_ABORT:
rmrf(SSH_HOSTKEYS_NEXT);
return SR_ERR_OK;
case SR_EV_DONE:
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);
svc_change(session, event, "/infix-services:ssh", "ssh", "sshd");
}
return SR_ERR_OK;
default:
return SR_ERR_OK;
}
if (sr_get_data(session, "/ietf-keystore:keystore/asymmetric-keys//.", 0, 0, 0, &cfg) || !cfg) {
return SR_ERR_OK;
}
changes = lydx_get_descendant(cfg->tree, "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;
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);
continue;
}
if (strcmp(public_key_type, "infix-crypto-types:ssh-public-key-format")) {
INFO("Public key %s is not of SSH type", name);
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;
}
sr_release_data(cfg);
return rc;
}
int infix_services_init(struct confd *confd)
int infix_services_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd)
{
int rc;
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:mdns",
0, mdns_change, confd, &confd->sub);
REGISTER_MONITOR(confd->session, "ietf-system", "/ietf-system:system/hostname",
0, hostname_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:ssh",
0, ssh_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:web",
0, web_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:web/infix-services:console",
0, ttyd_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:web/infix-services:netbrowse",
0, netbrowse_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:web/infix-services:restconf",
0, restconf_change, confd, &confd->sub);
REGISTER_CHANGE(confd->session, "ieee802-dot1ab-lldp", "/ieee802-dot1ab-lldp:lldp",
0, lldp_change, confd, &confd->sub);
/* Store SSH keys */
REGISTER_CHANGE(confd->session, "ietf-keystore", "/ietf-keystore:keystore//.",
0, change_keystore_cb, confd, &confd->sub);
rc = lldp_change(session, config, diff, event, confd);
if (rc)
return rc;
rc = mdns_change(session, config, diff, event, confd); /* TODO: Depends on hostname changes */
if (rc)
return rc;
rc = ssh_change(session, config, diff, event, confd); /* TODO: Depends on keystore changes*/
if (rc)
return rc;
rc = web_change(session, config, diff, event, confd);
if (rc)
return rc;
rc = ttyd_change(session, config, diff, event, confd);
if (rc)
return rc;
rc = restconf_change(session, config, diff, event, confd);
if (rc)
return rc;
rc = netbrowse_change(session, config, diff, event, confd);
if (rc)
return rc;
return SR_ERR_OK;
fail:
ERROR("init failed: %s", sr_strerror(rc));
return rc;
}
+1 -1
View File
@@ -89,7 +89,7 @@ static int infix_system_sw_set_boot_order(sr_session_ctx_t *session, uint32_t su
return SR_ERR_OK;
}
int infix_system_sw_init(struct confd *confd)
int infix_system_sw_rpc_init(struct confd *confd)
{
int rc = 0;
+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.
+4 -3
View File
@@ -17,14 +17,15 @@
- name: Misc tests
suite: misc/all.yaml
- name: "IETF System"
suite: ietf_system/all.yaml
# Upgrade may leave wrong boot order
- case: meta/bootorder.py
infamy:
specification: False
- name: "IETF System"
suite: ietf_system/all.yaml
- name: "IETF Syslog"
suite: ietf_syslog/all.yaml
@@ -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
}
]
}
}
})
+1 -2
View File
@@ -14,7 +14,6 @@ image::topology.svg[Remote syslog topology, align=center, scaledwidth=75%]
. Set up topology and attach to client and server DUTs
. Configure client DUT as syslog client with server DUT as remote, and configure server DUT as syslog server
. Send security:notice log message from client
. Verify reception of client log message, incl. sorting to /log/security on server
. Send security:notice log message from client and verify reception of client log message, incl. sorting to /log/security on server
+7 -5
View File
@@ -6,6 +6,11 @@ Verify logging to remote, acting as a remote, and RFC5424 log format.
"""
import infamy
def syslog_check(clientssh, serverssh):
clientssh.runsh("logger -t test -m client -p security.notice TestMessage")
return serverssh.runsh("tail -n10 /log/security |grep 'test - client - TestMessage'").returncode == 0
with infamy.Test() as test:
with test.step("Set up topology and attach to client and server DUTs"):
env = infamy.Env()
@@ -142,11 +147,8 @@ with infamy.Test() as test:
}
})
with test.step("Send security:notice log message from client"):
clientssh.runsh("logger -t test -m client -p security.notice TestMessage")
with test.step("Send security:notice log message from client and verify reception of client log message, incl. sorting to /log/security on server"):
infamy.until(lambda: syslog_check(clientssh, serverssh) == True)
with test.step("Verify reception of client log message, incl. sorting to /log/security on server"):
infamy.until(lambda: serverssh.runsh(
"grep 'test - client - TestMessage' /log/security").returncode == 0)
test.succeed()
+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"
}
},
+1 -1
View File
@@ -10,7 +10,7 @@ def _get_ntp(target):
if data is None:
return None
return data["system-state"].get("infix-system:ntp", None) or data["system-state"].get("ntp", None)
return data.get("system-state", {}).get("infix-system:ntp", None) or data.get("system-state", {}).get("ntp", None)
def _get_ntp_sources(target):
+37 -12
View File
@@ -6,7 +6,7 @@
# Usage: ./utils/kernel-upgrade.sh <path-to-linux-dir>
#
set -e
set -e -o pipefail
# Parse arguments
if [ $# -ne 1 ]; then
@@ -139,15 +139,6 @@ rebase_kernel() {
log_info "Run 'git rebase --abort' to cancel or resolve conflicts manually"
exit 1
fi
# Push rebased branch to kkit remote
log_info "Pushing rebased branch to $KKIT_REMOTE..."
if git -C "$LINUX_DIR" push "$KKIT_REMOTE" "$LINUX_BRANCH" --force-with-lease; then
log_info "Successfully pushed to $KKIT_REMOTE"
else
log_error "Push failed"
exit 1
fi
}
# Update infix and run kernel refresh
@@ -195,8 +186,8 @@ update_infix() {
# Check if versions are the same
if [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
log_info "Kernel version unchanged ($OLD_VERSION), skipping refresh"
return 0
log_info "Kernel version unchanged ($OLD_VERSION), nothing to do"
exit 0
fi
# Run kernel refresh script
@@ -231,6 +222,16 @@ update_infix() {
else
log_warn "doc/ChangeLog.md not found, skipping changelog update"
fi
# Commit all changes
log_info "Committing changes to infix..."
git -C "$INFIX_DIR" add -A
if git -C "$INFIX_DIR" diff-index --quiet HEAD --; then
log_info "No changes to commit"
else
git -C "$INFIX_DIR" commit -m "Upgrade Linux kernel to $NEW_VERSION"
log_info "Changes committed"
fi
}
# Check for uncommitted changes
@@ -254,6 +255,29 @@ check_clean_working_tree() {
log_info "Working tree is clean"
}
# Push changes to remotes
push_changes() {
log_info "Pushing changes to remotes..."
# Push rebased linux branch to kkit remote
log_info "Pushing rebased linux branch to $KKIT_REMOTE..."
if git -C "$LINUX_DIR" push "$KKIT_REMOTE" "$LINUX_BRANCH" --force-with-lease; then
log_info "Successfully pushed linux branch to $KKIT_REMOTE"
else
log_error "Push to linux remote failed"
exit 1
fi
# Push infix branch to origin
log_info "Pushing infix branch to origin..."
if git -C "$INFIX_DIR" push origin "$INFIX_BRANCH"; then
log_info "Successfully pushed infix branch to origin"
else
log_error "Push to infix remote failed"
exit 1
fi
}
# Main execution
main() {
log_info "Starting automated kernel upgrade test..."
@@ -265,6 +289,7 @@ main() {
update_linux_kernel
rebase_kernel
update_infix
push_changes
log_info "Kernel upgrade completed successfully!"
}
+185 -23
View File
@@ -18,10 +18,12 @@ Usage:
$0 [OPTIONS] <board-name>
Options:
-b boot-dir Path to bootloader build directory (default: O= or output/)
-d Download bootloader files from latest-boot release
-f Force re-download of bootloader even if cached
-h This help text
-l List available boards
-o Override auto-detection of genimage.sh, use host installed version
-b boot-dir Path to bootloader build directory (default: O= or output/)
-r root-dir Path to rootfs build directory or rootfs.squashfs file (default: O= or output/)
Arguments:
@@ -44,8 +46,11 @@ Examples:
# Standalone with separate boot/rootfs builds:
$0 -b x-boot -r output raspberrypi-rpi64
# With downloaded rootfs:
$0 -b x-boot -r ~/Downloads/rootfs.squashfs friendlyarm-nanopi-r2s
# With downloaded rootfs and bootloader:
$0 -d -r ~/Downloads/rootfs.squashfs friendlyarm-nanopi-r2s
# Download bootloader and compose with Linux image in output directory:
$0 -od bananapi-bpi-r3
EOF
}
@@ -153,6 +158,83 @@ find_build_dir()
return 1
}
# Map board name to bootloader identifier
# Returns bootloader name used in artifact naming
get_bootloader_name()
{
board="$1"
case "$board" in
raspberrypi-rpi64)
echo "rpi64_boot"
;;
bananapi-bpi-r3)
echo "bpi_r3_boot"
;;
friendlyarm-nanopi-r2s)
echo "nanopi_r2s_boot"
;;
*)
err "Unknown bootloader for board: $board"
return 1
;;
esac
}
# Download and extract bootloader from latest-boot release
# Downloads to dl/bootloader/ cache and extracts to temporary build directory
# Returns the temporary directory path in SDCARD_TEMP_DIR variable
download_bootloader()
{
board="$1"
build_dir="$2"
bootloader=$(get_bootloader_name "$board") || return 1
if ! command -v gh >/dev/null 2>&1; then
die "gh CLI not found. Install it or build bootloader locally."
fi
# Set up download cache directory
dl_dir="${BR2_EXTERNAL_INFIX_PATH}/dl/bootloader"
mkdir -p "$dl_dir"
# Convert underscores to dashes for filename pattern matching
bootloader_pattern=$(echo "$bootloader" | tr '_' '-')
# Find or download bootloader tarball
tarball=$(ls "$dl_dir"/${bootloader_pattern}*.tar.gz 2>/dev/null | head -n1)
if [ -z "$tarball" ] || [ -n "$FORCE_DOWNLOAD" ]; then
if [ -n "$FORCE_DOWNLOAD" ] && [ -n "$tarball" ]; then
log "Force re-downloading bootloader..."
rm -f "$tarball" "$tarball.sha256"
else
log "Downloading bootloader $bootloader from latest-boot release..."
fi
if ! gh release download latest-boot \
--repo kernelkit/infix \
--pattern "*${bootloader_pattern}*.tar.gz" \
--dir "$dl_dir"; then
die "Failed downloading bootloader from latest-boot release. Check gh authentication and network connectivity."
fi
tarball=$(ls "$dl_dir"/${bootloader_pattern}*.tar.gz 2>/dev/null | head -n1)
[ -n "$tarball" ] || die "Downloaded tarball not found in $dl_dir"
else
log "Using cached bootloader: $(basename "$tarball")"
fi
# Create temporary directory for SD card composition
SDCARD_TEMP_DIR="${build_dir}/sdcard-${board}-$$"
mkdir -p "$SDCARD_TEMP_DIR"
log "Extracting bootloader to $SDCARD_TEMP_DIR..."
tar -xzf "$tarball" --strip-components=1 -C "$SDCARD_TEMP_DIR/"
log "Bootloader ready in temporary directory"
}
# Discover boot files for Raspberry Pi boot partition
# Scans rpi-firmware directory and builds file list for genimage
discover_rpi_boot_files()
@@ -189,8 +271,19 @@ discover_rpi_boot_files()
echo "$files"
}
while getopts "hlob:r:" opt; do
while getopts "hldfob:r:" opt; do
case $opt in
b)
BOOT_DIR="$OPTARG"
STANDALONE=1
;;
d)
DOWNLOAD_BOOT=1
STANDALONE=1
;;
f)
FORCE_DOWNLOAD=1
;;
h)
usage
exit 0
@@ -199,10 +292,6 @@ while getopts "hlob:r:" opt; do
list_boards
exit 0
;;
b)
BOOT_DIR="$OPTARG"
STANDALONE=1
;;
o)
OVERRIDE=1
;;
@@ -225,12 +314,19 @@ fi
# Standalone mode: set up environment from build directories
if [ -n "$STANDALONE" ]; then
if [ -z "$BOOT_DIR" ]; then
BOOT_DIR=$(find_build_dir) || die "Could not find boot directory. Use -b option"
fi
# In download mode without explicit dirs, default to same location for both
if [ -n "$DOWNLOAD_BOOT" ]; then
default_dir=$(find_build_dir) || die "Could not find build directory. Set O= or use -b/-r option"
: "${BOOT_DIR:=$default_dir}"
: "${ROOT_DIR:=$default_dir}"
else
if [ -z "$BOOT_DIR" ]; then
BOOT_DIR=$(find_build_dir) || die "Could not find boot directory. Use -b option"
fi
if [ -z "$ROOT_DIR" ]; then
ROOT_DIR=$(find_build_dir) || die "Could not find rootfs directory. Set O= or use -r option"
if [ -z "$ROOT_DIR" ]; then
ROOT_DIR=$(find_build_dir) || die "Could not find rootfs directory. Set O= or use -r option"
fi
fi
# Set up environment variables, some required by genimage.sh
@@ -248,22 +344,33 @@ if [ -n "$STANDALONE" ]; then
fi
done
# Copy rootfs and partition images to BINARIES_DIR
# Copy rootfs and partition images to BINARIES_DIR (skip if same directory)
mkdir -p "$BINARIES_DIR"
# Normalize paths for comparison
boot_images=$(cd "$BOOT_DIR" && pwd)/images
root_images=""
if [ -f "$ROOT_DIR" ]; then
# Direct path to rootfs.squashfs file
log "Copying rootfs from $ROOT_DIR to $BINARIES_DIR/rootfs.squashfs"
cp "$ROOT_DIR" "$BINARIES_DIR/rootfs.squashfs"
elif [ -f "$ROOT_DIR/images/rootfs.squashfs" ]; then
# Build directory with images/ - copy rootfs and partition images
log "Copying artifacts from $ROOT_DIR/images/ to $BINARIES_DIR/"
cp "$ROOT_DIR/images/rootfs.squashfs" "$BINARIES_DIR/"
# Copy partition images if they exist
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/images/$img" ]; then
cp "$ROOT_DIR/images/$img" "$BINARIES_DIR/"
fi
done
root_images=$(cd "$ROOT_DIR" && pwd)/images
# Only copy if different directories
if [ "$boot_images" != "$root_images" ]; then
# Build directory with images/ - copy rootfs and partition images
log "Copying artifacts from $ROOT_DIR/images/ to $BINARIES_DIR/"
cp "$ROOT_DIR/images/rootfs.squashfs" "$BINARIES_DIR/"
# Copy partition images if they exist
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/images/$img" ]; then
cp "$ROOT_DIR/images/$img" "$BINARIES_DIR/"
fi
done
else
log "Rootfs already in place at $BINARIES_DIR/"
fi
elif [ -f "$ROOT_DIR/rootfs.squashfs" ]; then
# Directory directly containing rootfs.squashfs
log "Copying rootfs from $ROOT_DIR/rootfs.squashfs"
@@ -292,6 +399,42 @@ fi
: "${RELEASE:=""}"
: "${INFIX_ID:="infix"}"
# Download bootloader if requested
if [ -n "$DOWNLOAD_BOOT" ]; then
# Save original output location
ORIGINAL_BINARIES_DIR="$BINARIES_DIR"
download_bootloader "$BOARD" "$BUILD_DIR"
# Now use the temporary directory for composition
BINARIES_DIR="$SDCARD_TEMP_DIR"
log "Linking rootfs files to $BINARIES_DIR..."
# Link rootfs and partition images to temp directory
if [ -f "$ROOT_DIR" ]; then
# Direct path to rootfs.squashfs file
ln -sf "$(realpath "$ROOT_DIR")" "$BINARIES_DIR/rootfs.squashfs"
elif [ -f "$ROOT_DIR/images/rootfs.squashfs" ]; then
ln -sf "$(realpath "$ROOT_DIR/images/rootfs.squashfs")" "$BINARIES_DIR/rootfs.squashfs"
# Link partition images if they exist
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/images/$img" ]; then
ln -sf "$(realpath "$ROOT_DIR/images/$img")" "$BINARIES_DIR/$img"
fi
done
elif [ -f "$ROOT_DIR/rootfs.squashfs" ]; then
ln -sf "$(realpath "$ROOT_DIR/rootfs.squashfs")" "$BINARIES_DIR/rootfs.squashfs"
# Link partition images if they exist
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/$img" ]; then
ln -sf "$(realpath "$ROOT_DIR/$img")" "$BINARIES_DIR/$img"
fi
done
else
die "Could not find rootfs.squashfs in $ROOT_DIR"
fi
fi
# Template expansion
log "Generating genimage configuration for $BOARD..."
@@ -343,6 +486,25 @@ else
run_genimage "$GENIMAGE_CFG"
fi
# Post-processing: move images and cleanup if using download mode
if [ -n "$DOWNLOAD_BOOT" ]; then
log "Moving SD card images to $ORIGINAL_BINARIES_DIR..."
mkdir -p "$ORIGINAL_BINARIES_DIR"
for img in "${BINARIES_DIR}"/*-sdcard.img*; do
if [ -f "$img" ]; then
mv "$img" "$ORIGINAL_BINARIES_DIR/"
log " $(basename "$img")"
fi
done
log "Cleaning up temporary directory..."
rm -rf "$SDCARD_TEMP_DIR"
# Update BINARIES_DIR for final output message
BINARIES_DIR="$ORIGINAL_BINARIES_DIR"
fi
log "SD card image created successfully:"
for img in "${BINARIES_DIR}"/*-sdcard.img*; do
if [ -f "$img" ]; then