Compare commits

...
124 Commits
Author SHA1 Message Date
Richard AlpeandGitHub d2e5c2cd29 Merge pull request #1054 from kernelkit/update-changelog
Update changelog for v25.05.0
2025-05-27 12:04:05 +02:00
Richard Alpe 8bca1bed9e Update changelog for v25.05.0
Signed-off-by: Richard Alpe <richard@bit42.se>
2025-05-27 11:04:25 +02:00
Mattias WalströmandGitHub b88841952a Merge pull request #1048 from kernelkit/fix-downgrade-documentation
Fix downgrade documentation
2025-05-27 09:55:53 +02:00
Jon-Olov Vatn 9c3e951286 Update downgrade doc to recommend explicitly store/use backup cfg
- relying on config version and files backed up during
  configuration is not enough.
- storing a configuration file before upgrading, to be used
  when downgrading, is more reliable.

[skip ci]
2025-05-27 08:04:52 +02:00
Jon-Olov VatnandGitHub c7c01e3616 Merge branch 'main' into fix-downgrade-documentation 2025-05-26 16:20:02 +02:00
Mattias WalströmandGitHub a6889fa8c5 Merge pull request #1053 from kernelkit/rpi4
Add support for Raspberry Pi 4B
2025-05-26 11:23:26 +02:00
Joachim Wiberg 6cd92c25a8 doc: introduce Raspberry Pi 4B support
Also, fix placement of the VisionFive2, it's not an Aarch64 boartd.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:37 +02:00
Joachim Wiberg ff4e20221c configs,rpi4: complete port, Infix booting
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:37 +02:00
Joachim Wiberg 808edf0a29 configs,rpi4: quirk, phy-detached-when-down
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:36 +02:00
Joachim Wiberg 3f68e297ef configs,rpi4: quirk, override /etc/watchdogd.conf
Apparently the BCM2835 watchdog driver does not hook into /dev/watchdog
but creates its own /dev/watchdog0, and is very picky about interval and
timeout as well it seems.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:36 +02:00
Joachim Wiberg 0158fe1adb configs,rpi4: add factory default password
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:35 +02:00
Joachim Wiberg 4345ec1694 configs,rpi4: switch to mainline kernel, fix console access
- switch to 6.12 LTS, same as other Infix boards
 - trim down kernel config a bit
 - sync defconfig with r2s to switch to Finit

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 23:15:35 +02:00
Joachim Wiberg ebace5020b configs: new rpi4_defconfig
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 20:37:27 +02:00
Joachim Wiberg ae4424dafe board/common: create infix-key.dtso as well for U-Boot
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 20:37:27 +02:00
Joachim Wiberg 50036e086d confd: fix yang description of dhcp client option
Update description to match new option name: subnet -> netmask.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-05-25 20:37:26 +02:00
Mattias WalströmandGitHub 6d53d92346 Merge pull request #1050 from kernelkit/upgrade-buildroot
Upgrade Buildroot to 2025.02.3 (LTS)
2025-05-23 16:00:04 +02:00
Ahmed Karic e0696c453a Upgrade Buildroot to 2025.02.3 (LTS) 2025-05-23 11:24:35 +02:00
Ahmed KaricandGitHub 8b9a452f0c Merge pull request #1051 from kernelkit/upgrade-kernel
Upgrade Linux kernel to 6.12.30 (LTS)
2025-05-23 09:30:18 +02:00
Ahmed Karic 8bc7858694 Upgrade Linux kernel to 6.12.30 (LTS) 2025-05-22 18:28:23 +02:00
Ahmed KaricandGitHub 0065aeef47 Merge pull request #1046 from kernelkit/resctrict-mount-in-cont
confd: Add mount constraint for container config
2025-05-22 18:26:29 +02:00
Ahmed Karic dfc350a783 confd: Validate container mount source path
If an invalid mount source path is specified, the container logs a
  "file not found" error and subsequently crashes.

  Adding a check inside the SR_EV_CHANGE event handler performs an
  early validation of the mount source path, allowing to reject
  configurations that reference non-existent or unreadable files before
  they are committed to the datastore.
2025-05-19 09:35:38 +02:00
Ahmed Karic 21a78c7639 confd: Add mount constraint for container config
This change ensures configuration correctness by enforcing that each
  container mount has either a source or content set. Without this, the
  system may generate invalid runtime arguments (src=(null)), leading
  to container startup failures.
2025-05-19 09:35:38 +02:00
Tobias WaldekranzandGitHub d6d621af36 Merge pull request #1047 from kernelkit/ix-board-fix
board: Make ix-board reusable from upper externals
2025-05-16 22:32:06 +02:00
Tobias Waldekranz e6ea2991e1 board: Make ix-board reusable from upper externals
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
2025-05-16 20:06:09 +02:00
Ahmed KaricandGitHub 00f69baace Merge pull request #1039 from kernelkit/verify-ieee-group-fwd
Verify ieee group fwd
2025-05-16 14:26:42 +02:00
Jon-Olov Vatn e5299fff1c Update downgrade doc to recommend explicitly store/use backup cfg
- relying on config version and files backed up during
  configuration is not enough.
- storing a configuration file before upgrading, to be used
  when downgrading, is more reliable.

[skip ci]
2025-05-16 12:46:24 +02:00
Jon-Olov Vatn d5e96a8232 Add link to netbooting howto from boot doc
[skip ci]
2025-05-15 13:00:52 +02:00
Ahmed Karic aff385f37f statd: Drop unsupported Chassis-ID and Port-ID Subtypes 2025-05-13 16:59:35 +02:00
Ahmed Karic e40fc33a55 doc: Document LLDP config support 2025-05-13 16:59:25 +02:00
Ahmed Karic 71b4aed05d test: Reorganize infix_services test 2025-05-13 16:59:12 +02:00
Ahmed Karic 50a94e8175 test: Verify ieee-group-forward LLDP 2025-05-13 16:58:57 +02:00
Ahmed Karic 2cbba5cf1f test: Cleanup topologies 2025-05-13 16:58:46 +02:00
Ahmed Karic 00f2a4cf33 statd: Refactor cli_pretty.py
- Sort commands in an alphabetical order
2025-05-13 16:58:38 +02:00
Ahmed Karic ec7891c097 statd: Fix function and class separation in cli_pretty.py
Fix new lines according to PEP8
2025-05-13 16:58:31 +02:00
Ahmed Karic 9c0a8e39ec klish-plugin-infix: fix indentation in infix.xml 2025-05-13 16:58:21 +02:00
Ahmed Karic 4a4325baa3 cli: Add CLI option to show LLDP neighbors 2025-05-13 16:58:14 +02:00
Ahmed Karic cae5cfd3f0 statd: Set default dest-mac-address for LLDP 2025-05-13 16:58:02 +02:00
Mattias WalströmandGitHub fa7c3d0a51 Merge pull request #1045 from kernelkit/activate-full-parallel
Use massive parallel in workflow for PRs
2025-05-13 10:40:37 +02:00
Mattias Walström 874c0a54c4 Use massive parallel in workflow for PRs
This to get quick turnaround development -> test when
doing PRs main branch builds and release builds are still
build sequentially.

Signed-off-by: Mattias Walström <lazzer@gmail.com>
2025-05-13 08:02:16 +02:00
Mattias WalströmandGitHub 6a2abd962f Merge pull request #989 from kernelkit/enable-full-parallel
Enable full parallel
2025-05-12 09:36:57 +02:00
Mattias WalströmandGitHub aa995e3321 Merge pull request #1044 from kernelkit/upgrade-kernel
Bump kernel to 6.12.28 (LTS)
2025-05-12 09:36:30 +02:00
Mattias Walström 0a74ba341f confd: Refactor when yang models are installed
And add support for BR2_PER_PACKAGE_DIR
2025-05-12 08:39:54 +02:00
Mattias Walström 13de8be58d confd: Fix some typos in sysrepo.inc
* Install correct yang file, instead of one that does not exist at all
* Remove some models only used in tests (and is causing troubble!)
2025-05-12 08:39:54 +02:00
Mattias Walström 606aee68db package/lowdown: Fix configure script for parallel builds 2025-05-12 08:39:53 +02:00
Mattias Walström e4578364b6 package: python-libyang: Add missing libyang dependency 2025-05-12 08:39:53 +02:00
Mattias Walström 5cdaebf5e8 package: nghttp-asio: Add missing openssl dependency 2025-05-12 08:39:52 +02:00
Mattias Walström 2848cd62bc package: landing: Create target directory before copying files
The directory may not exist in parallel builds
2025-05-12 08:39:52 +02:00
Mattias Walström 2303fc08aa Bump kernel to 6.12.28 (LTS) 2025-05-12 08:10:41 +02:00
Joachim WibergandGitHub 6277aaedcd Merge pull request #1043 from kernelkit/lacp-descr 2025-05-08 17:45:36 +02:00
Ahmed Karic f81b74458d confd: Correct description for LAG LACP modes
Fixes #1031
2025-05-08 15:54:59 +02:00
Mattias WalströmandGitHub 8f61879966 Merge pull request #1041 from kernelkit/imx8-graphic
imx8mp-evk: Add USB and HDMI support
2025-05-07 15:18:52 +02:00
Mattias Walström 5560266e19 containers: Allow to have multiple mounts
Only first mount was sent to podman.
2025-05-07 13:24:07 +02:00
Mattias Walström d8cbdd7d92 imx8mp-evk: Add USB and HDMI support 2025-05-07 13:24:04 +02:00
Jon-Olov VatnandGitHub 7560da80a7 Merge pull request #1038 from kernelkit/doc-upgrade-downgrade-policy
Doc upgrade/downgrade policy
2025-05-05 09:45:49 +02:00
Jon-Olov Vatn 413cb61112 Fixing review comments (upgrade/downgrade doc)
[skip ci]
2025-05-05 09:41:50 +02:00
Jon-Olov Vatn e3c6f749ad Fixing #1009 Doc upgrade/downgrade policy
- Add section on upgrading/downgrading and boot-order to system.md
- Add or update references on upgrading from other pages
  - boot.md (update ref)
  - cli/upgrade.md (add ref)
  - management.md (add ref)

[skip ci]
2025-05-02 16:21:12 +02:00
Mattias WalströmandGitHub a990e559f7 Merge pull request #1037 from kernelkit/upgrade-kernel
Upgrade kernel to 6.12.26 (LTS)
2025-05-02 13:46:15 +02:00
Mattias Walström a0b06b2593 Upgrade kernel to 6.12.26 (LTS) 2025-05-02 10:51:36 +02:00
Mattias WalströmandGitHub 354650c0a5 Merge pull request #1035 from kernelkit/upgrade-sysrepo
Upgrade sysrepo
2025-05-02 10:49:36 +02:00
Mattias Walström 12e5b4c1b4 test: Update files for unittest 2025-04-30 11:51:45 +02:00
Mattias Walström cfbdce1b90 Change timezone test to check timezone in operational instead of checking time
Libyang is smart, it "fixes" the timezone for you, this was overriden by a
hack in netconf.py and restconf.py, but what you really want is to see
in operational what the current timezone is.
2025-04-30 11:51:45 +02:00
Mattias Walström 0b29e9eee4 Bump sysrepo, netopeer2, libnetconf2, libyang, libyang-cpp, sysrepo-cpp, rousette 2025-04-30 11:51:44 +02:00
Mattias WalströmandGitHub 3f0a0e3df0 Merge pull request #1034 from kernelkit/update-changelog
Update changelog for v25.04.0
2025-04-30 09:45:26 +02:00
Mattias Walström 3b261b331d Update changelog for v25.04.0 2025-04-30 08:58:56 +02:00
Richard AlpeandGitHub 066ec71736 Merge pull request #1030 from kernelkit/allow-user-sysrepo-access
Allow user sysrepo access
2025-04-29 15:02:39 +02:00
Tobias WaldekranzandGitHub 71295e0e37 Merge pull request #1027 from kernelkit/add-mqprio-quirk
imx8mp-evk: Disable mqprio for eth1
2025-04-28 16:57:36 +02:00
Richard Alpe ac89f94580 sysrepo: allow non-wheel users access to sysrepo data
Non-privileged users in the sys-cli group can now access sysrepo data.

The data is now solely protected by the NCAM rules and not Unix file
permissions. Any stray user that's not part of the (default) sys-cli
group still can't access syrepo, like users added from the shell.

Fixes #932

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-28 15:41:09 +02:00
Richard Alpe 399984082f Bump buildroot (still 2025.02.1)
Use new buildroot branching strategy where all our commits are placed
on top of a buildroot release on a branch named BR_RELEASE-kkit.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-28 15:32:10 +02:00
Mattias Walström 3375555911 imx8mp-evk: Disable mqprio for eth1
The kernel just hang, adding a quirk for it.
2025-04-28 13:44:19 +02:00
Tobias WaldekranzandGitHub 794872ca0c Merge pull request #1028 from kernelkit/bump-finit
Bump Finit to v4.12
2025-04-28 08:09:52 +02:00
Joachim Wiberg b7f110dbdc package/finit: bump to v4.12
- Improve notify:s6 readiness compatibility
 - Update `runparts` usage text
 - Fix variable overloading in urandom plugin
 - Fix buffer overwrite in urandom plugin, reported by Aaron Andersen

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-28 00:50:30 +02:00
Mattias WalströmandGitHub af20325cc4 Merge pull request #1026 from kernelkit/upgrade-kernel 2025-04-25 18:09:49 +02:00
Mattias Walström 7a5c9d0324 Upgrade kernel to 6.12.25 (LTS)
Also backport some fixes for freescale-imx8mp-evk
2025-04-25 13:04:37 +02:00
Mattias WalströmandGitHub a2533aa9c4 Merge pull request #1025 from kernelkit/upgrade-buildroot 2025-04-25 12:10:52 +02:00
Mattias Walström 4d650bad7f Upgrade buildroot to 2025.02.1 (LTS)
2025.02.1, released April 22nd, 2025

	Changes with potentially large impact:

	- gstreamer1 and related packages: updated from 1.22.x to 1.24.x.
	  1.22.x was already EOL when Buildroot 2025.02 was released, so
	  GStreamer should really already have been udpated to 1.24.x.
	  This update was needed to fix a lot of vulnerabilities.
	- frr: updated from 9.1.3 to 10.3. Version 9 is no longer
	  maintained upstream, and not in any distro either. This update
	  was needed to fix a vulernability.

	Important / security related fixes:

	- libmodsecurity: CVE-2025-27110.
	- tinyxml2: CVE-2024-50615.
	- xserver_xorg-server & xwayland: CVE-2024-9632, CVE-2025-26594,
	    CVE-2025-26595, CVE-2025-26596, CVE-2025-26597,  CVE-2025-26598,
	    CVE-2025-26599, CVE-2025-26600, CVE-2025-26601.
	- exim: CVE-2025-30232.
	- mbedtls: CVE-2025-27809, CVE-2025-27810.
	- libfreeglut: CVE-2024-24258, CVE-2024-24259.
	- libopenh264: CVE-2025-27091.
	- gstreamer1: CVE-2024-47834, CVE-2024-47835, CVE-2024-47778,
	    CVE-2024-47777 CVE-2024-47776, CVE-2024-47775, CVE-2024-47774,
	    CVE-2024-47615, CVE-2024-47613, CVE-2024-47607, CVE-2024-47606,
	    CVE-2024-47603, CVE-2024-47602, CVE-2024-47601, CVE-2024-47600,
	    CVE-2024-47599, CVE-2024-47598, CVE-2024-47597, CVE-2024-47596,
	    CVE-2024-47546, CVE-2024-47545, CVE-2024-47544, CVE-2024-47543,
	    CVE-2024-47542, CVE-2024-47541, CVE-2024-47540, CVE-2024-47539,
	    CVE-2024-47538, CVE-2024-47537.
	- augeas: CVE-2025-2588.
	- libndp: CVE-2024-5564.
	- python-jinja2: CVE-2025-27516.
	- python-django: CVE-2025-26699.
	- libarchive: CVE-2024-57970, CVE-2025-1632.
	- frr: CVE-2024-55553.

	Updated / fixed packages: libmodsecurity, intel-mediadriver,
	intel-vpl-gpu-rt, python-aerich, python-aiohttp, python-maturin,
	python-tortoise-orm, python-sqlalchemy, kodi-pvr-waipu, tor, mc,
	tinyxml2, libgeos, intel-vpl-gpu-rt, intel-mediadriver, ruby,
	ncftp, xserver_xorg-server, exim, mbedtls, gdb, freerdp, uclibc,
	libsoup3, cairo, zabbix, armadillo, spdlog, go, linux, linux-tools,
	gstreamer, linux-header, ethtool, apr, mali-driver, libcoap, libcap
	python-fastapi, python-twisted.

	Test Improvements:

	- linux-tools: selftests: Add path containing BPF binary.
	- testing: make time setting portable.
	- testing: set date in emulated machine.
	- testing: add git runtime test.
	- test_gstreamer1: fix test by using bootlin toolchain.

	Infrastructure updates/fixes:

	- kconfig: Handle backspace (^H) key.
	- xilinx-embeddedsw: fix menuconfig visualization.
	- DEVELOPERS: change arnout's address.
	- support/download/svn: use 'svn info' whith LC_ALL=C
	- glibc: disable on RISC-V ilp32f and lp64f, not supported.
	- dillo: Fix an issue related to _SITE url for make show-info.
	- pkg-stats: add -v/--verbose option

	Build issues/problems solved for packages:

	dillo, freerdp, freeswitch, gdb, glibc, linux-tools,
	mesa3d-demos, ncftp, tesseract-ocr,
	v4l2loopback, zabbix
2025-04-24 20:12:43 +02:00
Tobias WaldekranzandGitHub ff5b71b825 Merge pull request #1019 from kernelkit/move-operational
statd: Move operational from confd to statd (yanger)
2025-04-23 16:18:42 +02:00
Mattias Walström 2b5cf29bb9 statd: Add new README to describe statd
Whats required from your system and what to expect when you run it
outside Infix.
2025-04-23 13:45:50 +02:00
Mattias Walström 513c03a764 statd: Add script to install yang-tools locally (under /home)
This to be able to run statd locally on your computer.
2025-04-23 13:45:50 +02:00
Mattias Walström 5a982ab9ff statd: Allow to specify yanger path 2025-04-23 13:45:50 +02:00
Mattias Walström 4ea451362f yanger: DHCP: Fix bug when search exist but no nameserver
When running a DHCP test `resolvconf -l` looked like this:
admin@client:~$ resolvconf -l
search example.com # e5
admin@client:~$

This resulted in broken result when reading operational data from
system-state (which used resolvonf -l)
2025-04-23 13:45:49 +02:00
Mattias Walström 44be4e57f0 test: statd: Update unit testfiles 2025-04-23 13:45:49 +02:00
Mattias Walström dc0871a093 yanger: Do not fail if rauc or /run/system.json exist
This allowes to run statd on your computer.
2025-04-23 13:45:48 +02:00
Mattias Walström c6b44db18a statd: Move operational from confd to statd (yanger) 2025-04-23 13:45:48 +02:00
Mattias WalströmandGitHub a4def1379c Merge pull request #1018 from kernelkit/clean-srload 2025-04-14 07:40:45 +02:00
Mattias Walström 028ab7c1f9 srload: Cleanup when running outside buildtree
The original syntax did not work and the initial intention,
that root is always required is also false.
2025-04-11 20:31:43 +02:00
Mattias WalströmandGitHub cc03a59725 Merge pull request #1013 from kernelkit/move-yang-models-to-confd
Move yang models to confd
2025-04-11 13:45:26 +02:00
Mattias Walström 092964a10b confd: Install *all* YANG modules from confd
Sysrepo, netopeer etc are still responsible to install the modules in
target directory, this will make that we will discover quickly if something
is updated.

Also this enables rm -rf output/target/etc/sysrepo/data/* && make confd-rebuild
This will reinstall all modules again.
2025-04-11 08:21:51 +02:00
Mattias Walström d0277de958 srload: Add support for multiple search directories 2025-04-11 08:21:50 +02:00
Mattias WalströmandGitHub 2df84e20af Merge pull request #1016 from kernelkit/fix-ssh-migrate
Fix migration when SSH server settings exist
2025-04-11 08:20:34 +02:00
Mattias WalströmandGitHub 9de4633c13 Merge pull request #1017 from kernelkit/update-kernel
Upgrade linux kernel to 6.12.23 (LTS)
2025-04-10 19:50:39 +02:00
Mattias Walström 50f955c242 Upgrade linux kernel to 6.12.23 (LTS) 2025-04-10 15:21:36 +02:00
Mattias Walström f2f539b492 Fix migration when SSH server settings exist
This fix #1015
2025-04-10 14:29:56 +02:00
Joachim WibergandGitHub 2b439298fb Merge pull request #1014 from kernelkit/fix-migrate-version 2025-04-09 17:04:06 +02:00
Richard Alpe 2ef759a9d8 confd: remove prefix from version leaf in migrate
Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-09 15:51:11 +02:00
Mattias WalströmandGitHub 6fe4db8431 Merge pull request #1011 from kernelkit/update-kernel
Update kernel to 6.12.22 (LTS)
2025-04-07 18:44:55 +02:00
Mattias Walström b2525e29e1 Upgrade linux kernel to 6.12.22 (LTS) 2025-04-07 18:26:07 +02:00
Joachim WibergandGitHub 7ef5223fca Merge pull request #1010 from kernelkit/netboot-doc
Netboot HowTo

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 17:57:56 +02:00
Joachim Wiberg 323bfc9d66 doc: add netboot howto, for developers
[skip ci]

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 17:56:59 +02:00
Mattias WalströmandGitHub d6be23fa6b Merge pull request #1012 from kernelkit/run-migrate-script-locally
Run migrate script locally
2025-04-07 17:07:21 +02:00
Mattias Walström c7c2998e33 Require a valid sha256 checksum for all package downloaded 2025-04-07 16:57:17 +02:00
Mattias Walström 184ed470d7 kernel-refresh.sh: Update linux hash on update 2025-04-07 16:57:17 +02:00
Richard Alpe 75352a9f77 confd: add no log option (-e) to migrate script
Write logs to stderr instead of syslog. Useful when running on a
non-target system.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 15:20:54 +02:00
Richard Alpe e3c601f2fd confd: add script path option (-s) to migrate script
This allows a user to run in on any system which has the Infix source
code that contains the modification scripts.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 15:09:36 +02:00
Richard Alpe 0ab9e2a36a confd: fix indentation of bin/migrate
Don't mix tabs and spaces.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 14:57:17 +02:00
Joachim WibergandGitHub 7b20665cf9 Merge pull request #1004 from kernelkit/new-show-command
Add new show command

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 14:34:35 +02:00
Mattias WalströmandGitHub 3d86ecd2ee Merge pull request #1005 from kernelkit/fix-images
Change type of disk image
2025-04-07 09:41:01 +02:00
Richard Alpe 403b79d370 test: update unit test data (cli/show-software)
The software list from sysrepo is no longer reversed, the reverse now
happens in cli-pretty. This commit reflects that.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 09:06:29 +02:00
Richard Alpe 740ecbcc43 cli: integrate (use) new show command in cli 2025-04-07 09:06:28 +02:00
Richard Alpe 42af6eec30 show: add bash tab-completions
Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 09:06:27 +02:00
Richard Alpe c584af356b show: add new show tool written in python3
The reason for this is:
1) We want to use the same fetch tool for all operational data, to
   avoid having duplicated xpaths scattered across the repo.
2) We want to call this directly from the CLI, which means it need to
   be escape safe. A unprivileged user shall be able to use it but not
   escape into a shell or do other malicious stuff.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 09:06:26 +02:00
Richard Alpe 827dc098e4 board/common: deprecate existing show command
There's several reasons for this. The main reason is that it was
developed as an intermediate way of getting system information when
the operational datastore was almost empty. There's not a lot of data
available in the operational datastore and we shall rely on that data
primarily. This command isn't safe to run from a jailed CLI as i
doesn't validate input and run commands directly in the shell, making
it hard to protect against a CLI jail break.

In upcoming patches we will introduce a new show tool that relies
solely on operational data and which sanitize the user input.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-04-07 09:06:25 +02:00
Richard Alpe bc5dd949d7 cli: fix indentation of infix.xml 2025-04-07 09:06:20 +02:00
Mattias Walström 4a932dec11 Update changelog for 2025.04 2025-04-07 08:20:21 +02:00
Mattias Walström d5c5e38604 CI: Store qcow2 disk images as release artififacts
This to make it easier to use  GNS3 appliance file from
GNS3 marketplace.
2025-04-07 08:16:34 +02:00
Mattias Walström 02080bfb6c qeneth: Move Infix test templates from qeneth to Infix 2025-04-07 08:16:33 +02:00
Mattias Walström d3fa51e4fa Use qcow2 for disk image instead of raw image
This make the release bundle much smaller, the disk image size
change from 512M to 2xsizeof(squashimage)
2025-04-07 08:16:33 +02:00
Mattias Walström 6cfe5f8c58 Fix symlink in release packages
Fix #1002
2025-04-07 08:16:33 +02:00
Mattias Walström b4f3e4eab8 migrate: Fix typo resulting in not logging correctly 2025-04-07 08:16:32 +02:00
Joachim WibergandGitHub b188e781ee Merge pull request #1007 from kernelkit/r2s-fixes
Fix NanoPi R2S Regression

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 08:16:09 +02:00
Joachim Wiberg 8156179f1b doc: update ChangeLog for v25.04 release cycle
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 06:22:19 +02:00
Joachim Wiberg 55632eebaa utils: update usage text with example, add -f
- Update usage text for readability, add example
 - Reindent getopts case and add -h
 - Allow 'git rm -f' to remove already staged patches

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 06:06:42 +02:00
Joachim Wiberg 71b11026bb configs/r2s_defconfig: bump kernel to 6.12.21 (LTS)
- Bump kernel to 6.12.21, same as other tier one boards
 - Fix #1006 byt enabling netlink for ethtool (now works!)
 - Sync defconfigs:
   - LIBXCRYPT now in an rdep of another package
   - Disable FORCE check hashes for now
 - Drop patches for 6.10 tree (r2s kernel)
 - Port RTL8153b patch for R2S LAN LED support

Fixes #1006

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 05:54:54 +02:00
Joachim Wiberg 2b28733fda confd: set correct file version of migrated files in backup
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 05:32:05 +02:00
Joachim Wiberg 8c115e17c4 board/common: set wheel group on /cfg/backup dir
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2025-04-07 05:32:05 +02:00
403 changed files with 25036 additions and 7726 deletions
+21 -2
View File
@@ -13,7 +13,11 @@ on:
required: false
default: true
type: boolean
parallell:
description: 'Massive parallel build of each image'
required: false
default: true
type: boolean
jobs:
build:
name: Build Infix ${{ matrix.target }}
@@ -71,6 +75,7 @@ jobs:
echo "tgz=infix-$target.tar.gz" >> $GITHUB_OUTPUT
echo "flv=$flavor" >> $GITHUB_OUTPUT
echo "Building target ${target}${flavor}_defconfig"
- name: Restore Cache of dl/
uses: actions/cache@v4
with:
@@ -96,10 +101,24 @@ jobs:
run: |
make test-unit
- name: Prepare parallel build
id: parallel
run: |
if [ "${{ ((github.event.inputs.parallel == 'true' && github.event_name == 'workflow_dispatch') || (github.ref_name != 'main' && github.event_name != 'workflow_dispatch')) }}" == "true" ]; then
echo "BR2_PER_PACKAGE_DIRECTORIES=y" >> output/.config
MAKE="make -j$((`getconf _NPROCESSORS_ONLN` / 2 + 2))"
echo "Building in parallel with -j$((`getconf _NPROCESSORS_ONLN` / 2 + 2))"
else
echo "Disabling parallel build"
MAKE="make"
fi
echo "MAKE=$MAKE" >> $GITHUB_OUTPUT
- name: Build ${{ matrix.target }}${{ steps.vars.outputs.flv }}
run: |
echo "Building ${{ matrix.target }}${{ steps.vars.outputs.flv }}_defconfig ..."
make
eval "${{ steps.parallel.outputs.MAKE }}"
- name: Check SBOM from Build
run: |
+11 -1
View File
@@ -95,6 +95,11 @@ jobs:
name: artifact-${{ matrix.target }}
path: output/*.tar.gz
- uses: actions/upload-artifact@v4
with:
name: artifact-disk-image-${{ matrix.target }}
path: output/images/*.qcow2
release:
name: Release Infix ${{ github.ref_name }}
needs: build
@@ -141,6 +146,11 @@ jobs:
for file in *.tar.gz; do
sha256sum $file > $file.sha256
done
if ls *.qcow2 &>/dev/null; then
for file in *.qcow2; do
sha256sum "$file" > "$file.sha256"
done
fi
- name: Extract ChangeLog entry ...
run: |
@@ -155,7 +165,7 @@ jobs:
makeLatest: ${{ steps.rel.outputs.latest }}
discussionCategory: ${{ steps.rel.outputs.cat }}
bodyFile: release.md
artifacts: "*.tar.gz*"
artifacts: "*.tar.gz*,*.qcow2*"
- name: Summary
run: |
+6 -4
View File
@@ -93,12 +93,14 @@ The [following boards](board/aarch64/README.md) are fully supported:
- Marvell CN9130 CRB
- Marvell EspressoBIN
- Microchip SparX-5i PCB135 (eMMC)
- StarFive VisionFive2
- Raspberry Pi 4B
- NanoPi R2S
An x86_64 build is also available, primarily intended for development
and testing, but can also be used for evaluation and demo purposes. For
more information, see: [Infix in Virtual Environments](doc/virtual.md).
Additionally, StarFive VisionFive2, a RISC-V based two-port router, and
an x86_64 build is also available. The latter is primarily intended for
development and testing, but can also be used for evaluation and demo
purposes. For more information, see: [Infix in Virtual
Environments](doc/virtual.md).
> See the [GitHub Releases](https://github.com/kernelkit/infix/releases)
> page for our pre-built images. The *[Latest Build][]* has bleeding
-2
View File
@@ -230,7 +230,6 @@ CONFIG_MAC80211_LEDS=y
CONFIG_RFKILL=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
# CONFIG_ETHTOOL_NETLINK is not set
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_IOV=y
@@ -481,7 +480,6 @@ CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_GPIO=m
CONFIG_I2C_RK3X=y
CONFIG_I2C_SLAVE=y
@@ -0,0 +1,14 @@
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts 2025-04-28 00:13:06.880003668 +0200
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts 2025-04-28 00:14:17.708941263 +0200
@@ -14,6 +14,11 @@
chosen {
/* 8250 auxiliary UART instead of pl011 */
stdout-path = "serial1:115200n8";
+
+ infix {
+ /* Default admin user password: 'admin' */
+ factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A";
+ };
};
cam1_reg: regulator-cam1 {
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
root=/dev/mmcblk0p2 rootwait console=tty1 console=ttyAMA0,115200
+41
View File
@@ -0,0 +1,41 @@
# Please note that this is only a sample, we recommend you to change it to fit
# your needs.
# You should override this file using BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE.
# See http://buildroot.org/manual.html#rootfs-custom
# and http://elinux.org/RPiconfig for a description of config.txt syntax
start_file=start4.elf
fixup_file=fixup4.dat
kernel=u-boot.bin
device_tree=bcm2711-rpi-4-b.dtb
dtoverlay=rpi-env
dtoverlay=infix-key
# To use an external initramfs file
#initramfs rootfs.cpio.gz
# Disable overscan assuming the display supports displaying the full resolution
# If the text shown on the screen disappears off the edge, comment this out
disable_overscan=1
# How much memory in MB to assign to the GPU on Pi models having
# 256, 512 or 1024 MB total memory
gpu_mem_256=100
gpu_mem_512=100
gpu_mem_1024=100
# Enable UART0 for serial console on ttyAMA0
enable_uart=1
force_turbo=1
#dtoverlay=miniuart-bt
# Run as fast as firmware / board allows
arm_boost=1
# enable 64bits support
arm_64bit=1
# Enable early debugging info
uart_2ndstage=1
+71
View File
@@ -0,0 +1,71 @@
image boot.vfat {
vfat {
files = {
#BOOT_FILES#
}
}
size = 32M
}
image cfg.ext4 {
empty = true
temporary = true
size = 16M
ext4 {
label = "cfg"
}
}
image var.ext4 {
empty = true
temporary = true
size = 512M
ext4 {
label = "var"
use-mke2fs = true
}
}
image sdcard.img {
hdimage {
partition-table-type = "gpt"
}
partition boot {
partition-type-uuid = EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
bootable = "true"
image = "boot.vfat"
}
partition aux {
partition-uuid = D4EF35A0-0652-45A1-B3DE-D63339C82035
image = "aux.ext4"
}
partition primary {
partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4
bootable = true
size = 200M
image = "rootfs.squashfs"
}
partition secondary {
partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4
bootable = true
size = 200M
image = "rootfs.squashfs"
}
partition cfg {
partition-uuid = 7aa497f0-73b5-47e5-b2ab-8752d8a48105
image = "cfg.ext4"
}
partition var {
partition-uuid = 8046A06A-E45A-4A14-A6AD-6684704A393F
image = "var.ext4"
}
}
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# Armbian firmware installs to /lib/firmware but driver wants the
# file(s) in /lib/firmware/brcm/
if [ -f "${TARGET_DIR}/lib/firmware/BCM4345C0.hcd" ]; then
mv "${TARGET_DIR}/lib/firmware/BCM4345C0.hcd" "${TARGET_DIR}/lib/firmware/brcm/"
fi
+43
View File
@@ -0,0 +1,43 @@
#!/bin/sh
set -e
BOARD_DIR=$(dirname "$0")
GENIMAGE_CFG="${BUILD_DIR}/genimage.cfg"
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
# Device trees are installed for distro boot (syslinux.conf), but on RPi
# we need them for the SPL, which feeds the TPL (U-Boot) for use instead
# of the (built-in) control DT other platforms use.
find "${TARGET_DIR}/boot" -type f -name '*.dtb' -exec cp '{}' "${BINARIES_DIR}/" \;
# We've asked U-Boot previously to build overlays for us: Infix signing
# key and our ixboot scripts. Make sure here they are installed in the
# proper directory so genimage can create the DOS partition the SPL
# reads config.txt from.
find "${BINARIES_DIR}" -type f -name '*.dtbo' -exec mv '{}' "${BINARIES_DIR}/rpi-firmware/overlays/" \;
# Create FILES array for the genimage.cfg generation
FILES=""
for f in "${BINARIES_DIR}"/*.dtb "${BINARIES_DIR}"/rpi-firmware/*; do
case "$f" in
*~|*.bak) continue ;;
esac
FILES="${FILES}\t\t\t\"${f#"${BINARIES_DIR}/"}\",\n"
done
KERNEL=$(sed -n 's/^kernel=//p' "${BINARIES_DIR}/rpi-firmware/config.txt")
FILES="${FILES}\t\t\t\"${KERNEL}\""
sed "s|#BOOT_FILES#|${FILES}|" "${BOARD_DIR}/genimage.cfg.in" > "${GENIMAGE_CFG}"
ROOTPATH_TMP=$(mktemp -d)
trap 'rm -rf \"$ROOTPATH_TMP\"' EXIT
rm -rf "${GENIMAGE_TMP}"
genimage \
--rootpath "${ROOTPATH_TMP}" \
--tmppath "${GENIMAGE_TMP}" \
--inputpath "${BINARIES_DIR}" \
--outputpath "${BINARIES_DIR}" \
--config "${GENIMAGE_CFG}"
@@ -0,0 +1,16 @@
default rpi4b
menu title Boot Menu
prompt 1
timeout 30
label rpi4b
menu label Infix on Raspberry Pi 4B
kernel /boot/Image
devicetree /boot/broadcom/bcm2711-rpi-4-b.dtb
append ${bootargs_root} 8250.nr_uarts=1 console=ttyS0,115200 ${bootargs_log} -- ${bootargs_user}
label rpi400
menu label Infix on Raspberry Pi 400
kernel /boot/Image
devicetree /boot/broadcom/bcm2711-rpi-400.dtb
append ${bootargs_root} 8250.nr_uarts=1 console=ttyS0,115200 ${bootargs_log} -- ${bootargs_user}
@@ -0,0 +1,193 @@
{
"ieee802-dot1ab-lldp:lldp": {
"infix-lldp:enabled": true
},
"ietf-interfaces:interfaces": {
"interface": [
{
"name": "lo",
"type": "infix-if-type:loopback",
"ietf-ip:ipv4": {
"address": [
{
"ip": "127.0.0.1",
"prefix-length": 8
}
]
},
"ietf-ip:ipv6": {
"address": [
{
"ip": "::1",
"prefix-length": 128
}
]
}
},
{
"name": "eth0",
"type": "infix-if-type:ethernet"
}
]
},
"ietf-keystore:keystore": {
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "genkey",
"public-key-format": "ietf-crypto-types:ssh-public-key-format",
"public-key": "",
"private-key-format": "ietf-crypto-types:rsa-private-key-format",
"cleartext-private-key": "",
"certificates": {}
}
]
}
},
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"groups": {
"group": [
{
"name": "admin",
"user-name": [
"admin"
]
}
]
},
"rule-list": [
{
"name": "admin-acl",
"group": [
"admin"
],
"rule": [
{
"name": "permit-all",
"module-name": "*",
"access-operations": "*",
"action": "permit",
"comment": "Allow 'admin' group complete access to all operations and data."
}
]
},
{
"name": "default-deny-all",
"group": [
"*"
],
"rule": [
{
"name": "deny-password-read",
"module-name": "ietf-system",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
},
"ietf-netconf-server:netconf-server": {
"listen": {
"endpoints": {
"endpoint": [
{
"name": "default-ssh",
"ssh": {
"tcp-server-parameters": {
"local-address": "::"
},
"ssh-server-parameters": {
"server-identity": {
"host-key": [
{
"name": "default-key",
"public-key": {
"central-keystore-reference": "genkey"
}
}
]
}
}
}
}
]
}
}
},
"ietf-system:system": {
"hostname": "rpi4",
"ntp": {
"enabled": true,
"server": [
{
"name": "ntp.org",
"udp": {
"address": "pool.ntp.org"
},
"iburst": true
}
]
},
"authentication": {
"user": [
{
"name": "admin",
"password": "$factory$",
"infix-system:shell": "bash"
}
]
},
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCAtLSBhIE5ldHdvcmsgT3BlcmF0aW5nIFN5c3RlbQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQuZ2l0aHViLmlvCictJy0tLSctJwo="
},
"infix-dhcp-client:dhcp-client": {
"client-if": [
{
"if-name": "eth0",
"option": [
{
"id": "netmask"
},
{
"id": "broadcast"
},
{
"id": "router"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "ntp-server"
}
]
}
]
},
"infix-meta:meta": {
"infix-meta:version": "1.2"
},
"infix-services:mdns": {
"enabled": true
},
"infix-services:web": {
"enabled": true,
"console": {
"enabled": true
},
"netbrowse": {
"enabled": true
},
"restconf": {
"enabled": true
}
}
}
@@ -0,0 +1,5 @@
{
"eth0": {
"phy-detached-when-down": true
}
}
@@ -0,0 +1,6 @@
# Broadcom BCM2835 Watchdog timer
device /dev/watchdog0 {
timeout = 60
interval = 5
safe-exit = true
}
+3
View File
@@ -0,0 +1,3 @@
# CONFIG_MMC_PCI is not set
CONFIG_OF_OVERLAY_LIST="rpi-env infix-key"
# CONFIG_ENV_IS_IN_FAT is not set
+27
View File
@@ -0,0 +1,27 @@
/dts-v1/;
/plugin/;
&{/} {
config {
environment {
vendor = "infix";
preboot = "run ixpreboot";
ixbootdelay = "0.5";
bootdelay = "-2";
bootmenu_delay = "10";
boot_targets = "mmc1";
ethprime = "eth0";
bootcmd = "run ixboot";
ixpreboot = /incbin/("scripts/ixpreboot.sh");
ixbtn-devmode = "setenv dev_mode yes; echo Enabled";
ixbtn-factory = "echo \"No button available, use bootmenu\"";
ixfactory = /incbin/("scripts/ixfactory.sh");
ixboot = /incbin/("scripts/ixboot.sh");
ixbootslot = /incbin/("scripts/ixbootslot.sh");
ixprepblk = /incbin/("scripts/ixprepblk.sh");
ixprepdhcp = /incbin/("scripts/ixprepdhcp.sh");
};
};
};
+5 -3
View File
@@ -127,7 +127,7 @@ bootdata=
diskimg=disk.img
bootimg=
bootpart=
tmpimage=$(mktemp)
while getopts "a:b:B:n:s:" opt; do
case ${opt} in
a)
@@ -166,7 +166,7 @@ awk \
-vimgsize=$imgsize \
-vcfgsize=$cfgsize \
-vvarsize=$varsize \
-vdiskimg=$diskimg \
-vdiskimg=$tmpimage \
-vbootimg="$bootimg" -vbootpart="$bootpart" \
'{
sub(/@TOTALSIZE@/, total);
@@ -211,5 +211,7 @@ genimage \
--rootpath "$root" \
--tmppath "$tmp" \
--inputpath "$BINARIES_DIR" \
--outputpath "$BINARIES_DIR" \
--config "$root/genimage.cfg"
qemu-img convert -c -O qcow2 "$tmpimage" "$BINARIES_DIR/$diskimg"
rm "$tmpimage"
+3 -3
View File
@@ -23,7 +23,7 @@ if [ -n "$IMAGE_ID" ]; then
else
NAME="$INFIX_ID"-$(echo "$BR2_ARCH" | tr _ - | sed 's/x86-64/x86_64/')
fi
diskimg=disk.img
diskimg=disk.qcow2
ver()
{
@@ -48,7 +48,7 @@ fi
load_cfg DISK_IMAGE
if [ "$DISK_IMAGE" = "y" ]; then
ixmsg "Creating Disk Image"
diskimg="${NAME}-disk$(ver).img"
diskimg="${NAME}-disk$(ver).qcow2"
bootcfg=
if [ "$DISK_IMAGE_BOOT_DATA" ]; then
bootcfg="-b $DISK_IMAGE_BOOT_DATA -B $DISK_IMAGE_BOOT_OFFSET"
@@ -90,7 +90,7 @@ if [ "$BR2_TARGET_ROOTFS_SQUASHFS" = "y" ]; then
rel=$(ver)
ln -sf rootfs.squashfs "$BINARIES_DIR/${NAME}${rel}.img"
if [ -n "$rel" ]; then
ln -sf "$BINARIES_DIR/${NAME}${rel}.img" "$BINARIES_DIR/${NAME}.img"
ln -sf "${NAME}${rel}.img" "$BINARIES_DIR/${NAME}.img"
fi
fi
+5 -5
View File
@@ -120,7 +120,7 @@ rootfs_args()
echo -n "-device sd-card,drive=mmc "
echo -n "-drive id=mmc,file=$CONFIG_QEMU_ROOTFS,if=none,format=raw "
elif [ "$CONFIG_QEMU_ROOTFS_VSCSI" = "y" ]; then
echo -n "-drive file=$CONFIG_QEMU_ROOTFS.qcow2,if=virtio,format=qcow2,bus=0,unit=0 "
echo -n "-drive file=qemu.qcow2,if=virtio,format=qcow2,bus=0,unit=0 "
fi
}
@@ -316,13 +316,13 @@ gdb_args()
run_qemu()
{
if [ "$CONFIG_QEMU_ROOTFS_VSCSI" = "y" ]; then
if ! qemu-img check "${CONFIG_QEMU_ROOTFS}.qcow2"; then
rm -f "${CONFIG_QEMU_ROOTFS}.qcow2"
if ! qemu-img check "qemu.qcow2"; then
rm -f "qemu.qcow2"
fi
if [ ! -f "${CONFIG_QEMU_ROOTFS}.qcow2" ]; then
if [ ! -f "qemu.qcow2" ]; then
echo "Creating qcow2 disk image for Qemu ..."
qemu-img create -f qcow2 -o backing_file="$CONFIG_QEMU_ROOTFS" \
-F raw "${CONFIG_QEMU_ROOTFS}.qcow2" > /dev/null
-F qcow2 "qemu.qcow2" > /dev/null
fi
fi
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
if [ $# -lt 2 ]; then
echo "usage: $0 <quirk-name> <ifname>"
exit 1
fi
quirk=$1
ifname=$2
if [ -f "/etc/product/interface-quirks.json" ]; then
echo "$(jq -r --arg iface "$ifname" --arg quirk "$quirk" '.[$iface][$quirk] // "false"' /etc/product/interface-quirks.json)"
else
echo "false"
fi
@@ -43,6 +43,7 @@ while [ "$1" ]; do
txqs="$2"
shift 2
[ $(/usr/libexec/infix/has-quirk "broken-mqprio" "$iface") = "true" ] && echo "Skipping $iface, does not support mqprio" && continue
[ $txqs -lt 2 ] && continue
[ $txqs -gt 8 ] && txqs=8
@@ -4,10 +4,14 @@
# the migrate tool inserts old version in name before .cfg extension.
CONFIG_FILE="/cfg/startup-config.cfg"
BACKUP_FILE="/cfg/backup/startup-config.cfg"
mkdir -p "$(dirname "$BACKUP_FILE")"
BACKUP_DIR="$(dirname "$BACKUP_FILE")"
mkdir -p "$BACKUP_DIR"
chown root:wheel "$BACKUP_DIR"
chmod 0770 "$BACKUP_DIR"
if [ ! -f "$CONFIG_FILE" ]; then
note "No $(basename "$CONFIG_FILE" .cfg) yet, likely factory reset."
logger -I $$ -k -p user.notice -t $(basename "$0") "No $(basename "$CONFIG_FILE" .cfg) yet, likely factory reset."
exit 0
elif migrate -cq "$CONFIG_FILE"; then
exit 0
+2 -2
View File
@@ -550,7 +550,7 @@ while [ "$1" != "" ]; do
;;
-m | --mount)
shift
mount="--mount=$1"
mount="$mount --mount=$1"
;;
--manual)
manual=true
@@ -696,7 +696,7 @@ case $cmd in
oci)
find $BUILTIN $DOWNLOADS -type f 2>/dev/null
;;
*)
*)
podman ps $all --format "{{.Names}}"
;;
esac
+11 -2
View File
@@ -17,14 +17,23 @@ endef
# U-Boot build tree. This will then be built in to the final U-Boot
# image's control DT via the CONFIG_DEVICE_TREE_INCLUDES option (see
# extras.config).
#
# Some platforms, most notably Raspberry Pi, load the device tree
# from the SPL, effectively overriding the built-in control DT.
# For that we bundle an overlay that can be included instead.
define UBOOT_PRE_BUILD_INSTALL_KEY
$(HOST_DIR)/bin/dtc <(echo '/dts-v1/; / { signature {}; };') >$(@D)/infix-key.dtb
$(HOST_DIR)/bin/dtc -a 1024 <(echo '/dts-v1/; / { signature {}; };') \
>$(@D)/infix-key.dtb
$(foreach key, \
$(call qstrip,$(TRUSTED_KEYS_DEVELOPMENT_PATH)) $(call qstrip,$(TRUSTED_KEYS_EXTRA_PATH)),\
$(call uboot-add-pubkey,$(key),$(@D)/infix-key.dtb))
$(HOST_DIR)/bin/dtc -I dtb -O dts \
<$(@D)/infix-key.dtb \
| sed -e 's:/dts-v[0-9]\+/;::' >$(@D)/arch/$(UBOOT_ARCH)/dts/infix-key.dtsi
| sed -e 's:/dts-v[0-9]\+/;::' \
| tee $(@D)/arch/$(UBOOT_ARCH)/dts/infix-key.dtsi \
| sed -e '1i\/dts-v1/;\n/plugin/;\n' -e '/^$$/d' -e 's:/ {:\&{/} {:' \
>$(@D)/arch/$(UBOOT_ARCH)/dts/infix-key.dtso
rm $(@D)/infix-key.dtb
endef
UBOOT_PRE_BUILD_HOOKS += UBOOT_PRE_BUILD_INSTALL_KEY
+5 -1
View File
@@ -27,13 +27,14 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.21"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_DBUS_CXX=y
@@ -139,6 +140,7 @@ BR2_PACKAGE_CURIOS_HTTPD=y
BR2_PACKAGE_CURIOS_NFTABLES=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
@@ -164,6 +166,8 @@ BR2_PACKAGE_TETRIS=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_PACKAGE_GETENT=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
DISK_IMAGE_BOOT_BIN=y
+5 -1
View File
@@ -27,13 +27,14 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.21"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_DBUS_CXX=y
@@ -119,6 +120,7 @@ BR2_PACKAGE_CONFD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
@@ -137,6 +139,8 @@ BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_PACKAGE_GETENT=y
DISK_IMAGE_BOOT_BIN=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
+6 -4
View File
@@ -8,7 +8,6 @@ BR2_CCACHE=y
BR2_CCACHE_DIR="${BR2_EXTERNAL_INFIX_PATH}/.ccache"
BR2_ENABLE_DEBUG=y
BR2_GLOBAL_PATCH_DIR="${BR2_EXTERNAL_INFIX_PATH}/patches"
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_TARGET_GENERIC_HOSTNAME="infix"
BR2_TARGET_GENERIC_ISSUE="Infix by KernelKit"
BR2_INIT_FINIT=y
@@ -30,7 +29,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image
BR2_ROOTFS_POST_SCRIPT_ARGS="-c $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/genimage.cfg"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.10.3"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_PATCH="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/rk3328-nanopi-r2s-dts.patch"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/r2s/linux_defconfig"
@@ -42,6 +41,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_INFIX_PATH)/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_LINUX_FIRMWARE=y
@@ -74,7 +74,6 @@ BR2_PACKAGE_PYTHON_GUNICORN=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
BR2_PACKAGE_LIBSSH2=y
BR2_PACKAGE_LIBSSH2_OPENSSL=y
BR2_PACKAGE_LIBXCRYPT=y
BR2_PACKAGE_LIBOPENSSL_BIN=y
BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
@@ -178,6 +177,7 @@ INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
@@ -201,8 +201,10 @@ BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
BR2_PACKAGE_TETRIS=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_PACKAGE_GETENT=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
# GNS3_APPLIANCE is not set
+4
View File
@@ -39,6 +39,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_INFIX_PATH)/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_LINUX_FIRMWARE=y
@@ -169,6 +170,7 @@ BR2_PACKAGE_CONFD=y
# BR2_PACKAGE_CONFD_TEST_MODE is not set
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
@@ -194,6 +196,8 @@ BR2_PACKAGE_TETRIS=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_PACKAGE_GETENT=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
# GNS3_APPLIANCE is not set
+201
View File
@@ -0,0 +1,201 @@
BR2_aarch64=y
BR2_cortex_a72=y
BR2_ARM_FPU_VFPV4=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y
BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY=y
BR2_DL_DIR="${BR2_EXTERNAL_INFIX_PATH}/dl"
BR2_CCACHE=y
BR2_CCACHE_DIR="${BR2_EXTERNAL_INFIX_PATH}/.ccache"
BR2_GLOBAL_PATCH_DIR="board/raspberrypi/patches ${BR2_EXTERNAL_INFIX_PATH}/patches"
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_TARGET_GENERIC_HOSTNAME="infix"
BR2_TARGET_GENERIC_ISSUE="Infix by KernelKit"
BR2_INIT_FINIT=y
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_ROOTFS_DEVICE_TABLE="system/device_table.txt ${BR2_EXTERNAL_INFIX_PATH}/board/common/xattrs"
BR2_ROOTFS_MERGED_USR=y
# BR2_TARGET_ENABLE_ROOT_LOGIN is not set
BR2_SYSTEM_BIN_SH_BASH=y
BR2_TARGET_GENERIC_GETTY_PORT="@console"
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
BR2_SYSTEM_DHCP="eth0"
BR2_SYSTEM_DEFAULT_PATH="/bin:/sbin:/usr/bin:/usr/sbin"
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA C.UTF-8"
BR2_GENERATE_LOCALE="en_US en_CA C.UTF-8"
BR2_TARGET_TZ_INFO=y
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/rootfs"
BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_PATCH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/bcm2711-rpi-4-b-dts.patch"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/bcm2711_defconfig"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2711-rpi-4-b broadcom/bcm2711-rpi-400"
BR2_LINUX_KERNEL_DTB_KEEP_DIRNAME=y
BR2_LINUX_KERNEL_INSTALL_TARGET=y
BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL_INFIX_PATH)/board/common/busybox_defconfig"
BR2_PACKAGE_XZ=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_ARMBIAN_FIRMWARE=y
BR2_PACKAGE_ARMBIAN_FIRMWARE_AP6255=y
BR2_PACKAGE_BRCMFMAC_SDIO_FIRMWARE_RPI=y
BR2_PACKAGE_LINUX_FIRMWARE=y
BR2_PACKAGE_LINUX_FIRMWARE_BRCM_BCM43XX=y
BR2_PACKAGE_LINUX_FIRMWARE_BRCM_BCM43XXX=y
BR2_PACKAGE_LINUX_FIRMWARE_BRCM_BCM4366B1=y
BR2_PACKAGE_LINUX_FIRMWARE_BRCM_BCM4366C0=y
BR2_PACKAGE_RPI_FIRMWARE=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}/board/aarch64/rpi/config.txt"
BR2_PACKAGE_RPI_FIRMWARE_CMDLINE_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rpi/cmdline.txt"
BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_DBUS_TRIGGERD=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_EVEMU=y
BR2_PACKAGE_EVTEST=y
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_INPUT_EVENT_DAEMON=y
BR2_PACKAGE_MDIO_TOOLS=y
BR2_PACKAGE_RNG_TOOLS=y
BR2_PACKAGE_UBOOT_TOOLS_FIT_SUPPORT=y
BR2_PACKAGE_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y
BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y
BR2_PACKAGE_PYTHON3=y
BR2_PACKAGE_PYTHON_GUNICORN=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
BR2_PACKAGE_LIBSSH2=y
BR2_PACKAGE_LIBSSH2_OPENSSL=y
BR2_PACKAGE_LIBOPENSSL_BIN=y
BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
BR2_PACKAGE_ONIGURUMA=y
BR2_PACKAGE_AVAHI_DAEMON=y
BR2_PACKAGE_AVAHI_DEFAULT_SERVICES=y
BR2_PACKAGE_CHRONY=y
BR2_PACKAGE_CONNTRACK_TOOLS=y
BR2_PACKAGE_DNSMASQ=y
BR2_PACKAGE_ETHTOOL=y
BR2_PACKAGE_FPING=y
BR2_PACKAGE_FRR=y
BR2_PACKAGE_HOSTAPD=y
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
BR2_PACKAGE_IPROUTE2=y
BR2_PACKAGE_IPTABLES_NFTABLES=y
BR2_PACKAGE_IPUTILS=y
BR2_PACKAGE_IW=y
BR2_PACKAGE_LLDPD=y
BR2_PACKAGE_MSTPD=y
BR2_PACKAGE_NETCALC=y
BR2_PACKAGE_NETCAT_OPENBSD=y
BR2_PACKAGE_NETSNMP=y
BR2_PACKAGE_NFTABLES=y
BR2_PACKAGE_NGINX=y
BR2_PACKAGE_NGINX_HTTP_SSL_MODULE=y
BR2_PACKAGE_NGINX_HTTP_V2_MODULE=y
BR2_PACKAGE_NMAP=y
BR2_PACKAGE_NMAP_NCAT=y
BR2_PACKAGE_NMAP_NMAP=y
BR2_PACKAGE_NMAP_NPING=y
BR2_PACKAGE_OPENRESOLV=y
BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_TRACEROUTE=y
BR2_PACKAGE_ULOGD=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIRELESS_REGDB=y
BR2_PACKAGE_WIRELESS_TOOLS=y
BR2_PACKAGE_WPA_SUPPLICANT=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_TTYD=y
BR2_PACKAGE_GETENT=y
BR2_PACKAGE_HTOP=y
BR2_PACKAGE_IRQBALANCE=y
BR2_PACKAGE_KMOD_TOOLS=y
BR2_PACKAGE_PWGEN=y
BR2_PACKAGE_RAUC=y
BR2_PACKAGE_RAUC_DBUS=y
BR2_PACKAGE_RAUC_GPT=y
BR2_PACKAGE_RAUC_NETWORK=y
BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
BR2_TARGET_ROOTFS_SQUASHFS=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_TARGET_UBOOT=y
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)/board/aarch64/rpi/uboot/extras.config"
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)/board/aarch64/rpi/uboot/rpi-env.dtso"
BR2_PACKAGE_HOST_DOSFSTOOLS=y
BR2_PACKAGE_HOST_E2FSPROGS=y
BR2_PACKAGE_HOST_ENVIRONMENT_SETUP=y
BR2_PACKAGE_HOST_GENEXT2FS=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_KMOD_XZ=y
BR2_PACKAGE_HOST_MTOOLS=y
BR2_PACKAGE_HOST_RAUC=y
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y
BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
INFIX_VENDOR_HOME="https://github.com/kernelkit"
INFIX_IMAGE_ID="${INFIX_ID}-rpi4"
INFIX_DESC="Infix is a Network Operating System based on Linux. It can be set up both as a switch, with offloading using switchdev, and a router with firewalling."
INFIX_HOME="https://github.com/kernelkit/infix/"
INFIX_DOC="https://github.com/kernelkit/infix/tree/main/doc"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
BR2_PACKAGE_FINIT_PLUGIN_MODULES_LOAD=y
BR2_PACKAGE_FINIT_PLUGIN_RTC=y
BR2_PACKAGE_FINIT_RTC_DATE="2024-11-04 10:54:00"
BR2_PACKAGE_FINIT_RTC_FILE="/var/lib/misc/rtc"
BR2_PACKAGE_FINIT_PLUGIN_TTY=y
BR2_PACKAGE_FINIT_PLUGIN_URANDOM=y
BR2_PACKAGE_IITO=y
BR2_PACKAGE_KEYACK=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_LANDING=y
BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_NETBROWSE=y
BR2_PACKAGE_PODMAN=y
BR2_PACKAGE_PODMAN_DRIVER_BTRFS=y
BR2_PACKAGE_PODMAN_DRIVER_DEVICEMAPPER=y
BR2_PACKAGE_PODMAN_DRIVER_VFS=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_TETRIS=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
SDCARD_AUX=y
+5 -1
View File
@@ -26,7 +26,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.21"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -34,6 +34,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_DBUS_CXX=y
@@ -141,6 +142,7 @@ BR2_PACKAGE_CURIOS_HTTPD=y
BR2_PACKAGE_CURIOS_NFTABLES=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
@@ -166,6 +168,8 @@ BR2_PACKAGE_TETRIS=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_PACKAGE_GETENT=y
TRUSTED_KEYS=y
TRUSTED_KEYS_DEVELOPMENT=y
GNS3_APPLIANCE_RAM=512
+6 -5
View File
@@ -7,13 +7,14 @@ BR2_CCACHE=y
BR2_CCACHE_DIR="${BR2_EXTERNAL_INFIX_PATH}/.ccache"
BR2_ENABLE_DEBUG=y
BR2_GLOBAL_PATCH_DIR="${BR2_EXTERNAL_INFIX_PATH}/patches"
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
BR2_TARGET_GENERIC_HOSTNAME="ix"
BR2_TARGET_GENERIC_ISSUE="Infix by KernelKit"
BR2_INIT_FINIT=y
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_ROOTFS_DEVICE_TABLE="system/device_table.txt ${BR2_EXTERNAL_INFIX_PATH}/board/common/xattrs"
# BR2_TARGET_ENABLE_ROOT_LOGIN is not set
BR2_ROOTFS_MERGED_USR=y
# BR2_TARGET_ENABLE_ROOT_LOGIN is not set
BR2_SYSTEM_BIN_SH_BASH=y
BR2_TARGET_GENERIC_GETTY_PORT="@console"
BR2_TARGET_GENERIC_GETTY_TERM="xterm"
@@ -26,7 +27,7 @@ BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INF
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.21"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.30"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/x86_64/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -34,6 +35,7 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_DBUS_CXX=y
@@ -50,10 +52,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y
BR2_PACKAGE_UBOOT_TOOLS_FIT_CHECK_SIGN=y
BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y
BR2_PACKAGE_PYTHON3=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
BR2_PACKAGE_LIBSSH2=y
BR2_PACKAGE_LIBSSH2_OPENSSL=y
BR2_PACKAGE_LIBXCRYPT=y
BR2_PACKAGE_LIBOPENSSL_BIN=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_LIBMNL=y
@@ -83,6 +82,7 @@ BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_GETENT=y
BR2_PACKAGE_KMOD_TOOLS=y
BR2_PACKAGE_PWGEN=y
BR2_PACKAGE_RAUC=y
@@ -138,6 +138,7 @@ BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
TRUSTED_KEYS=y
+43 -1
View File
@@ -3,6 +3,45 @@ Change Log
All notable changes to the project are documented in this file.
[v25.05.0][] - 2025-05-27
-------------------------
### Changes
- Upgrade Buildroot to 2025.02.3 (LTS)
- Upgrade Linux kernel to 6.12.30 (LTS)
- Upgrade libyang to 3.12.2
- Upgrade sysrepo to 3.6.11
- Upgrade netopeer2 (NETCONF) to 2.4.1
- New hardware support: Raspberry Pi 4B (aarch64)
- Add documentation on Infix upgrading and downgrading, issue #1009
- Add HDMI and USB support for iMX8MP-evk
- Enforced strict format for LLDP destination MAC address:
- Only accepts colon-separated format: `01:80:C2:00:00:0E`
- Add `show lldp` command to show discovered neighbors per interface.
- Add configuration support for per-interface LLDP administrative status
### Fixes
- Fix containers with multiple mounts
- Correct description for LAG LACP modes
- Fix #1040: Add `mount` constraint for container config
[v25.04.0][] - 2025-04-30
-------------------------
### Changes
- Upgrade Linux kernel to 6.12.25 (LTS)
- Upgrade Buildroot to 2025.02.1 (LTS)
- Format for disk image (for QEMU) has changed to `qcow2`
### Fixes
- Fix #1002: Broken symlink in release package
- Fix #1006: NanoPi R2S corrupt startup, regression in Infix v25.02.0
- Bump R2S kernel, now same as tier one boards
- Fix #1015: Not possible to save custom SSH settings in startup-config
- Fix group owner and permissions of `/cfg/backup` directory
- Fix extraction of old version for `/cfg/backup/` files
- Fix configuration migration issues when upgrading
[v25.03.0][] - 2025-03-31
-------------------------
@@ -97,6 +136,7 @@ All notable changes to the project are documented in this file.
- Add support for GRE/GRETAP tunnels
- Add support for STP/RSTP on bridges
- Add support for VXLAN tunnels
- Add support for configuring global LLDP `message-tx-interval`
### Fixes
@@ -1529,7 +1569,9 @@ 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.03.0...HEAD
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v25.05.0...HEAD
[v25.05.0]: https://github.com/kernelkit/infix/compare/v25.04.0...v25.05.0
[v25.04.0]: https://github.com/kernelkit/infix/compare/v25.03.0...v25.04.0
[v25.03.0]: https://github.com/kernelkit/infix/compare/v25.02.0...v25.03.0
[v25.02.0]: https://github.com/kernelkit/infix/compare/v25.01.0...v25.02.0
[v25.01.0]: https://github.com/kernelkit/infix/compare/v24.11.0...v25.01.0
+6 -3
View File
@@ -63,7 +63,7 @@ bootloader's validation procedure, user configuration is kept to a
minimum. Two settings are available:
- **Boot order**: Since Infix maintains two copies of its software image,
and as some bootloaders support netbooting, the order in which boot
and as some bootloaders support [netbooting][2], the order in which boot
sources are considered can be configured. To select the active
source, use [RAUC][]:
@@ -349,5 +349,8 @@ can funtion reasonably well without a persistent `/var`, loosing
If `var` is not available, Infix will still persist `/var/lib` using
`cfg` as the backing storage.
[^1]: See [CLI Upgrade](cli/upgrade.md) for information on upgrading
via CLI.
[^1]: See [Upgrading procedures and boot
order](system.md#upgrade-procedures-and-boot-order) for
information on upgrading via CLI.
[2]: netboot.md
+5
View File
@@ -39,7 +39,12 @@ The secondary partition (`rootfs.1`) has now been upgraded and will be used as
the *active* partition on the next boot. Leaving the primary partition, with
the version we are currently running, intact in case of trouble.
See [upgrading procedures and boot order][2] for more information on
upgrading.
[^1]: It is not possible to upgrade the partition we booted from. Thankfully
the underlying "rauc" subsystem keeps track of this. Hence, to upgrade
both partitions you must reboot to the new version (to verify it works)
and then repeat the same command.
[2]: ../system.md#upgrade-procedures-and-boot-order
+10 -5
View File
@@ -131,6 +131,8 @@ This rebuilds (and installs) `foo` and `bar`, the `all` target calls
on Buildroot to finalize the target filesystem and generate the images.
The final `run` argument is explained below.
### `confd`
The Infix `src/confd/` is the engine of the system. Currently it is a
@@ -217,21 +219,24 @@ structure of an existing one. However, before making any changes, **always discu
them with the Infix core team**. This helps avoid issues later in development and
makes pull request reviews smoother.
Testing
-------
Manual testing can be done using Qemu by calling <kbd>make run</kbd>,
see also [Infix in Virtual Environments](virtual.md).
see also [Infix in Virtual Environments](virtual.md), or on a physical
device by upgrading to the latest build or "[netbooting](netboot.md)"
and running the image from RAM. The latter is how most board porting
work is done -- **much quicker** change-load-test cycles.
The Infix automated test suite is built around Qemu and [Qeneth][2], see:
* [Testing](testing.md)
* [Docker Image](../test/docker/README.md)
With any new feature added to Infix, it is essential to include a
relevant test case. See the
[Test Development](testing.md#test-development) section for guidance
on adding test cases.
With any new feature added to Infix, it is essential to include relevant
test case(s). See the [Test Development](testing.md#test-development)
section for guidance on adding test cases.
Reviewing
+58 -1
View File
@@ -46,7 +46,7 @@ admin@infix-c0-ff-ee:~$
## LLDP
Infix supports LLDP (IEEE 802.1AB). For a device with factory default
Infix supports LLDP (IEEE 802.1AB). For a device with factory default
settings, the link-local IPv6 address can be read from the Management
Address TLV using *tcpdump* or other sniffing tools[^1]:
@@ -131,6 +131,10 @@ tcpdump: listening on tap0, link-type EN10MB (Ethernet), snapshot length 262144
linux-pc:#
```
The following capabilities are available via NETCONF/RESTCONF or the Infix CLI.
### LLDP Enable/Disable
The LLDP service can be disabled using the following commands.
```
@@ -140,6 +144,59 @@ admin@infix-c0-ff-ee:/config/> leave
admin@infix-c0-ff-ee:/>
```
To reenable it from the CLI config mode:
```
admin@test-00-01-00:/config/> set lldp enabled
admin@test-00-01-00:/config/> leave
```
### LLDP Message Transmission Interval
By default, LLDP uses a `message-tx-interval` of 30 seconds, as defined
by the IEEE standard. Infix allows this value to be customized.
To change it using the CLI:
```
admin@test-00-01-00:/config/> set lldp message-tx-interval 1
admin@test-00-01-00:/config/> leave
```
### LLDP Administrative Status per Interface
Infix supports configuring the LLDP administrative status on a per-port
basis. The default mode is `tx-and-rx`, but the following options are
also supported:
- `rx-only` Receive LLDP packets only
- `tx-only` Transmit LLDP packets only
- `disabled` Disable LLDP on the interface
Example configuration:
```
admin@test-00-01-00:/config/> set lldp port e8 dest-mac-address 01:80:C2:00:00:0E admin-status disabled
admin@test-00-01-00:/config/> set lldp port e5 dest-mac-address 01:80:C2:00:00:0E admin-status rx-only
admin@test-00-01-00:/config/> set lldp port e6 dest-mac-address 01:80:C2:00:00:0E admin-status tx-only
admin@test-00-01-00:/config/> leave
```
> [!NOTE]
> The destination MAC address must be the standard LLDP multicast
> address: `01:80:C2:00:00:0E`.
### Displaying LLDP Neighbor Information
In CLI mode, Infix also provides a convenient `show lldp` command to
list LLDP neighbors detected on each interface:
```
admin@test-00-01-00:/> show lldp
INTERFACE REM-IDX TIME CHASSIS-ID PORT-ID
e5 1 902 00:a0:85:00:04:01 00:a0:85:00:04:07
e6 3 897 00:a0:85:00:03:01 00:a0:85:00:03:07
e8 2 901 00:a0:85:00:02:01 00:a0:85:00:02:05
```
## mDNS-SD
+8
View File
@@ -193,3 +193,11 @@ admin@example:/config/web/> edit restconf
admin@example:/config/web/restconf/> no enabled
admin@example:/config/web/restconf/>
```
# System Upgrade
See [upgrading procedures and boot order][1] for information on
upgrading.
[1]: system.md#upgrade-procedures-and-boot-order
+130
View File
@@ -0,0 +1,130 @@
Netboot HowTo
=============
This document describes how to set up network booting U-Boot devices on
a LAN, e.g., when working with an evaluation board or other embedded
system. The most secure way to do this is with a local LAN between a PC
and the device.
Instead of setting up everything in U-Boot to download the Linux Image,
device tree, and initramfs, we will let U-Boot download a script with
instructions to run. When you have multiple systems (boards) this
quickly becomes a lot easier to manage.
> [!NOTE]
> Instructions in this HowTo assume a Debian based development system,
> e.g., Ubuntu or Linux Mint.
## Network Interface Setup
For two dedicated network interfaces, here `eth2` and `eth3` (ymmv), we
create an old-style interfaces config[^1] with the following content:
```
# /etc/network/interfaces.d/gimli
auto eth2
iface eth2 inet static
address 192.168.0.1
netmask 255.255.255.0
auto eth3
iface eth3 inet manual
```
> [!TIP]
> Use configuration file names in `.d/` directories that make sense and
> can easily be remembered. Here we use the hostname of the PC.
## DHCP/TFTP Server Setup
The examples given here use `dnsmasq`, which provides both DHCP and TFTP
server support. The same can be achieved with other implementations.
Similar to `interfaces.d`, dnsmasq has an `/etc/dnsmasq.d` directory so
we can use "snippets" instead of modifying `/etc/dnsmasq.conf` directly.
Add a file called `/etc/dnsmasq.d/gimli`.
Initial content:
```
# Remember IP address handed out to BOOTP clients
bootp-dynamic
# Disable check-if-ip-address-is-already-used
no-ping
# Enable TFTP server, use /srv/ftp, same as any FTP server, useful
# when using the same images for system upgrade as for netbooting.
enable-tftp
tftp-root=/srv/ftp
```
> [!CAUTION]
> First of all, make sure you DO NOT accidentally set up dnsmasq so that
> it starts acting as a DHCP server also on your office LAN! Follow the
> instructions below for more details.
If you have many interfaces used for lab equipment and only one office
LAN interface, then use something like this:
```
# Disable DHCP server on loopback and office LAN (eth0)
except-interface=lo
except-interface=eth0
```
To further lock this down, we only run the DHCP server on each of the
interfaces used for lab equipment, with a dedicated IP range as well:
```
# Currently I have an imx8mp-evk on eth2, so on my system I have a
# symlink bootfile-eth2 -> netboot.scr
interface=eth2
dhcp-range=192.168.0.100,192.168.0.199,1h
dhcp-boot=tag:eth2,bootfile-eth2
```
## Bootfile netboot.scr
The bootfile U-Boot retrieves from the TFTP server is a script that
looks like this, `netboot.sh`:
```sh
setenv ramdisk_addr_r 0x58000000
setenv fdt_addr_r 0x50400000
setenv autoboot off
tftp ${fdt_addr_r} imx8mp-evk/imx8mp-evk.dtb
tftp ${kernel_addr_r} imx8mp-evk/Image
tftp ${ramdisk_addr_r} imx8mp-evk/rootfs.squashfs
setenv bootargs console=ttymxc1,115200 root=/dev/ram0 brd.rd_size=500000 rauc.slot=net
booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}
```
U-Boot cannot read script files directly, so we need to wrap it with a
FIT format header, this is done by first converting it on the PC:
```
$ mkimage -T script -d netboot.sh netboot.scr
```
The output is `netboot.scr` which we symlink to above in the dnsmasq
setup step.
## U-Boot Commands
U-Boot is a maze of environment variables, some with values, some wrap
commands, and most are undocumented. We will use a prefix for our
variables to ensure we do not overwrite anything you may want to use
later.
```sh
==> setenv ixboot 'dhcp && source \${fileaddr}'
==> saveenv
```
[^1]: To prevent NetworkManager from automatically managing the interfaces.
+432
View File
@@ -323,7 +323,439 @@ reference ID, stratum, time offsets, frequency, and root delay.
> The system uses `chronyd` Network Time Protocol (NTP) daemon. The
> output shown here is best explained in the [Chrony documentation][4].
## Upgrade procedures and boot order
For resilience purposes, Infix maintains two software
images referred to as the _primary_ and _secondary_ partition image.
In addition, some bootloaders support [netbooting][6].
The _boot order_ defines which image is tried first, and is listed
with the CLI `show software` command. It also shows Infix version
installed per partition, and which image was used when booting (`STATE
booted`).
```
admin@example:/> show software
BOOT ORDER
primary secondary net
NAME STATE VERSION DATE
primary booted v25.01.0 2025-04-25T10:15:00+00:00
secondary inactive v25.01.0 2025-04-25T10:07:20+00:00
admin@example:/>
```
YANG support for upgrading Infix, inspecting and _modifying_ the
boot-order, is defined in [infix-system-software][5].
### Upgrading Infix
Upgrading Infix is done one partition at a time. If the system has
booted from one partition, an `upgrade` will apply to the other
(inactive) partition.
1. Download and unpack the release to install. Make the image *pkg*
bundle available at some URL[^10]
2. (Optional) Backup the startup configuration
3. Assume the unit has booted the `primary` image. Then running the
`upgrade` command installs a new image on the `secondary`
partition
4. As part of a successful upgrade, the boot-order is implictly
changed to boot the newly installed image
5. Reboot the unit
6. The unit now runs the new image. To upgrade the remaining partition
(`primary`), run the same upgrade command again, and (optionally)
reboot to verify the upgrade
> [!CAUTION]
> During boot (step 5), the unit may
> [migrate](#configuration-migration) the startup configuration for
> any syntax changes. It is therefore important that you make sure to
> upgrade the other partition as well after reboot, of course after
> having verified your setup.
The CLI example below shows steps 2-5.
*Backup startup configuration:* It is recommended to backup the
startup configuration before performing an upgrade. The backup is
useful if the upgrade fails, and makes a later
[downgrade](#downgrading-infix) smoother to conduct.
```
admin@example:/> dir /cfg
/cfg directory
backup/ ssl/ startup-config.cfg
admin@example:/> copy /cfg/startup-config.cfg /cfg/v25.01.0-startup-config.cfg
admin@example:/> dir /cfg
/cfg directory
backup/ ssl/ startup-config.cfg v25.01.0-startup-config.cfg
admin@example:/>
```
*Upgrade:* Here the image *pkg bundle* was made available via TFTP.
```
admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.03.1.pkg
installing
0% Installing
0% Determining slot states
10% Determining slot states done.
...
98% Copying image to rootfs.1
99% Copying image to rootfs.1
99% Copying image to rootfs.1 done.
99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.03.1.pkg` succeeded
admin@example:/>
```
*Reboot:* The unit will boot on the other partition, with the newly
installed image. The `Loading startup-config` step conducts migration
of startup configuration if applicable.
```
admin@example:/> reboot
[ OK ] Stopping Static routing daemon
[ OK ] Stopping Zebra routing daemon
...
[ OK ] Loading startup-config
[ OK ] Verifying self-signed https certificate
[ OK ] Update DNS configuration
[ OK ] Starting Status daemon
Infix -- a Network Operating System v25.03.1 (ttyS0)
example login: admin
Password:
.-------.
| . . | Infix -- a Network Operating System
|-. v .-| https://kernelkit.org
'-'---'-'
Run the command 'cli' for interactive OAM
admin@example:~$ cli
See the 'help' command for an introduction to the system
admin@example:/> show software
BOOT ORDER
secondary primary net
NAME STATE VERSION DATE
primary inactive v25.01.0 2025-04-25T10:15:00+00:00
secondary booted v25.03.1 2025-04-25T10:24:31+00:00
admin@example:/>
```
As shown, the *boot order* has been updated, so that *secondary* is
now the preferred boot source.
To upgrade the remaining partition (`primary`), run the `upgrade URL`
command again, and (optionally) reboot.
### Configuration Migration
The example above illustrated an upgrade from Infix v25.01.0 to
v25.03.1. Inbetween these versions, YANG configuration definitions
changed slightly (more details given below).
During boot, Infix inspects the `version` meta information within the
startup configuration file to determine if configuration migration is
needed. In this specific case, the configuration file has version
`1.4` while the booted software expects version `1.5` (the
configuration version numbering differs from the Infix image version
numbering). The startup configuration is migrated to `1.5`
definitions and stored, while a backup previous startup configuration
is stored in directory `/cfg/backup/`.
```
admin@example:/> dir /cfg/backup/
/cfg/backup/ directory
startup-config-1.4.cfg
admin@example:/>
```
The modifications made to the startup configuration can be viewed by
comparing the files from the *shell*. An example is shown below.
```
admin@example:/> exit
admin@example:~$ diff /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg
--- /cfg/backup/startup-config-1.4.cfg
+++ /cfg/startup-config.cfg
...
- "public-key-format": "ietf-crypto-types:ssh-public-key-format",
+ "public-key-format": "infix-crypto-types:ssh-public-key-format",
...
- "private-key-format": "ietf-crypto-types:rsa-private-key-format",
+ "private-key-format": "infix-crypto-types:rsa-private-key-format",
...
- "version": "1.4"
+ "version": "1.5"
...
admin@example:~$
```
### Downgrading Infix
Downgrading to an earlier Infix version is possible, however,
downgrading is **not** guaranteed to work smoothly. In particular,
when the unit boots up with the downgraded version, it may fail to
apply the *startup config*, and instead apply its [failure config][7].
We consider two cases: downgrading with or without applying a backup
startup configuration before rebooting.
In both cases we start out with a unit running Infix v25.03.1, and
wish to downgrade to v25.01.0.
```
admin@example:/> show software
BOOT ORDER
primary secondary net
NAME STATE VERSION DATE
primary booted v25.03.1 2025-04-25T11:36:26+00:00
secondary inactive v25.03.1 2025-04-25T10:24:31+00:00
admin@example:/>
```
#### Downgrading when applying a backup startup configuration
This is the recommended approach to downgrade, given that you have a
backup configuration available. The objective is to avoid ending up
with the unit in *failure config*.
1. Find the backup configuration file.
2. Run `upgrade URL` to install Infix image to downgrade to.
3. Copy backup startup configuration to current startup configuration
(from shell).
4. Reboot.
*Find the backup configuration file:*
Assume you have a backup startup config for the Infix version to
downgrade to (here Infix v25.01.0, config `version 1.4`).
The preferred approach is to use a startup configuration backed up
when running Infix v25.01.0 on the unit. See the section on [upgrading
Infix](#upgrading-infix) above for more information. In the example
below, there is a backup file available named
*v25.01.0-startup-config.cfg*
```
admin@example:/> dir /cfg
/cfg directory
backup/ ssl/ startup-config.cfg v25.01.0-startup-config.cfg
admin@example:/>
```
The alternative is to use a startup config implicitly backed up by the
system as part of [configuration migration](#configuration-migration).
```
admin@example:/> dir /cfg/backup/
/cfg/backup/ directory
startup-config-1.4.cfg
admin@example:/>
```
> [!CAUTION] Using a backup configuration file stored when the unit
> was running the old version (e.g., v25.01.0-startup-config.cfg) is
> preferred. Although backup files stored due to configuration
> migration (e.g., startup-config-1.4.cfg) usually works too if the
> configuration file version (`1.4`) matches, there are
> situations when the system may fail to apply it as described below.
The *configuration file version* (`1.4`) is only incremented when
changes in YANG configuration syntax mandates it to handle
*upgrading*. Say the next Infix version includes a new feature
setting, it can still have version `1.4`, as upgrading to it would not
need migration. If a user then enables the new feature setting, the
new configuration will no longer be compatible with the previous *Infix
version*. A downgrade after enabling new features risks ending up with
the unit in *failure config*.
*Use `upgrade` command to downgrade:*
```
admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
0% Installing
0% Determining slot states
10% Determining slot states done.
...
99% Copying image to rootfs.1 done.
99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>
```
*Apply the backup configuration file:*
It is recommended to use a backup configuration file for the Infix version to
downgrade to, if there is one available.
```
admin@example:/> copy /cfg/v25.01.0-startup-config.cfg /cfg/startup-config.cfg
Overwrite existing file /cfg/startup-config.cfg (y/N)? y
admin@example:/>
```
An alternative is to use a backup file stored when the system
conducted a [configuration migration](#configuration-migration). See
the *caution* note above.
```
admin@example:/> copy /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg
Overwrite existing file /cfg/startup-config.cfg (y/N)? y
admin@example:/>
```
*Reboot:*
The unit will come up with the applied backup configuration.
```
admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
...
[ OK ] Bootstrapping YANG datastore
[ OK ] Starting Configuration daemon
[ OK ] Loading startup-config
[ OK ] Update DNS configuration
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon
Infix -- a Network Operating System v25.01.0 (ttyS0)
example login:
```
> [!NOTE]
> If the unit despite these measures ends up in *failure config*, see
> the next section for more information on how to recover.
#### Downgrading without applying a backup startup configuration
This procedure assumes you have access to the unit's console port and
its default login credentials[^9].
1. Downgrade
2. Reboot
3. Login with unit's default credentials
4. Conduct factory reset
5. (Then go on configure the unit as you wish)
*Use `upgrade` command to downgrade:*
```
admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
0% Installing
0% Determining slot states
10% Determining slot states done.
...
99% Copying image to rootfs.1 done.
99% Updating slots done.
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>
```
*Reboot:*
Conduct a reboot. During boot, the unit fails to apply the existing
startup configuration (config version `1.5` while software expects
version `1.4` or earlier), and instead applies its [failure
config][7]. This is what is seen on the console when this situation
occurs. Note that the login prompt displays `failed` as part of the
*hostname*.
```
admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
...
[ OK ] Verifying SSH host keys
[ OK ] Bootstrapping YANG datastore
[ OK ] Starting Configuration daemon
[FAIL] Loading startup-config
[ OK ] Loading failure-config
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon
Infix -- a Network Operating System v25.01.0 (ttyS0)
ERROR: Corrupt startup-config, system has reverted to default login credentials
failed-00-00-00 login:
```
To remedy a situation like this, you can login with the unit's *default
login credentials*, preferrably via a [console port][8].
The unit's default credentials are typically printed on a sticker on
the unit.
```
failed-00-00-00 login: admin
Password:
Run the command 'cli' for interactive OAM
admin@failed-00-00-00:~$
```
When it is *safe* from a network operations perspective, you can
conduct a factory reset and reboot. It is recommended to remove the
unit from any production network before doing this, as a factory reset
may enable undesired connectivity between the unit's ports.
```
admin@failed-00-00-00:~$ factory
Factory reset device (y/N)? y
factory: scheduled factory reset on next boot.
Reboot now to perform reset, (y/N)? y
[ OK ] Saving system time (UTC) to RTC
[ OK ] Stopping mDNS alias advertiser
...
[ OK ] Starting Configuration daemon
[ OK ] Loading startup-config
[ OK ] Update DNS configuration
[ OK ] Verifying self-signed https certificate
[ OK ] Starting Status daemon
[ OK ] Starting Status daemon
Please press Enter to activate this console.
Infix -- a Network Operating System v25.01.0 (ttyS0)
example login:
```
Continued configuration is done as with any unit after factory reset.
[1]: https://www.rfc-editor.org/rfc/rfc7317
[2]: https://github.com/kernelkit/infix/blob/main/src/confd/yang/infix-system%402024-02-29.yang
[3]: https://www.rfc-editor.org/rfc/rfc8341
[4]: https://chrony-project.org/doc/4.6.1/chronyc.html
[5]: https://github.com/kernelkit/infix/blob/main/src/confd/yang/confd/infix-system-software.yang
[6]: netboot.md
[7]: introduction.md#system-boot
[8]: management.md#console-port
[^9]: In failure config, Infix puts all Ethernet ports as individual
interfaces. With direct access, one can connect with e.g., SSH,
using link local IPv6 addresses. This as an alternative to
connecting via a console port.
[^10]: Set up an FTP/TFTP/SFTP or HTTP/HTTPS server on the same LAN.
[11]: scripting.md#-backup-configuration-using-sysrepocfg-and-scp
+1
View File
@@ -34,6 +34,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/python-libyang/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/python-statd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/python-yangdoc/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/show/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/libyang-cpp/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-cpp/Config.in"
+1 -52
View File
@@ -1,53 +1,2 @@
define inner-ix-board
$(2)_VERSION = ix-board
$(2)_LICENSE = BSD-3-Clause
$(2)_LICENSE_FILES = LICENSE
$(2)_SITE_METHOD = local
$(2)_SITE = $$(BR2_EXTERNAL_INFIX_PATH)/src/board/$(1)
$(2)_REDISTRIBUTE = NO
# The kernel must be built first.
$(2)_DEPENDENCIES += \
linux \
$$(BR2_MAKE_HOST_DEPENDENCY)
# This is only defined in some infrastructures (e.g. autotools, cmake),
# but not in others (e.g. generic). So define it here as well.
$(2)_MAKE ?= $$(BR2_MAKE)
define $(2)_DTBS_BUILD
@$$(call MESSAGE,"Building device tree blob(s)")
$$(LINUX_MAKE_ENV) $$($$(PKG)_MAKE) \
-C $$(LINUX_DIR) \
$$(LINUX_MAKE_FLAGS) \
$$($(2)_DTB_MAKE_OPTS) \
PWD=$$(@D)/dts \
M=$$(@D)/dts \
modules
endef
$(2)_POST_BUILD_HOOKS += $(2)_DTBS_BUILD
define $(2)_DTBS_INSTALL_TARGET
@$$(call MESSAGE,"Installing device tree blob(s)")
$$(TARGET_MAKE_ENV) $$(TARGET_CONFIGURE_OPTS) $$($$(PKG)_MAKE) \
-f $$(BR2_EXTERNAL_INFIX_PATH)/package/board/dtb-inst.makefile \
-C $$(@D)/dts \
DESTDIR="$$(TARGET_DIR)" \
install
endef
$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_DTBS_INSTALL_TARGET
define $(2)_OVERLAY_INSTALL_TARGET
@test -d $$(@D)/rootfs && \
$$(call MESSAGE,"Copying overlay") && \
$$(call SYSTEM_RSYNC,$$(@D)/rootfs,$(TARGET_DIR)) || \
true
endef
$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_OVERLAY_INSTALL_TARGET
endef
ix-board = $(call inner-ix-board,$(pkgname),$(call UPPERCASE,$(pkgname)))
include $(BR2_EXTERNAL_INFIX_PATH)/package/board/ix-board.mk
include $(sort $(wildcard $(BR2_EXTERNAL_INFIX_PATH)/package/board/*/*.mk))
@@ -20,6 +20,26 @@ define FREESCALE_IMX8MP_EVK_LINUX_CONFIG_FIXUPS
$(call KCONFIG_ENABLE_OPT,CONFIG_INTERCONNECT_IMX)
$(call KCONFIG_ENABLE_OPT,CONFIG_INTERCONNECT_IMX8MP)
$(call KCONFIG_ENABLE_OPT,CONFIG_REALTEK_PHY)
# For X
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM)
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM_ETNAVIV)
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE)
$(call KCONFIG_ENABLE_OPT,CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY)
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM_IMX8MP_HDMI_PVI)
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM_IMX_LCDIF)
$(call KCONFIG_ENABLE_OPT,CONFIG_INPUT_MOUSE)
$(call KCONFIG_ENABLE_OPT,CONFIG_INPUT_MOUSEDEV)
$(call KCONFIG_ENABLE_OPT,CONFIG_HID_GENERIC)
# For USB
$(call KCONFIG_DISABLE_OPT,CONFIG_USB)
$(call KCONFIG_ENABLE_OPT,CONFIG_USB)
$(call KCONFIG_ENABLE_OPT,CONFIG_USB_DWC3)
$(call KCONFIG_DISABLE_OPT,CONFIG_USB_DWC3_GADGET)
$(call KCONFIG_ENABLE_OPT,CONFIG_USB_DWC3_HOST)
$(call KCONFIG_ENABLE_OPT,CONFIG_ARM_IMX_BUS_DEVFREQ)
$(call KCONFIG_ENABLE_OPT,CONFIG_TYPEC_TCPCI)
$(call KCONFIG_ENABLE_OPT,CONFIG_TYPEC_SWITCH_GPIO)
endef
$(eval $(ix-board))
+51
View File
@@ -0,0 +1,51 @@
define inner-ix-board
$(2)_VERSION = ix-board
$(2)_LICENSE = BSD-3-Clause
$(2)_LICENSE_FILES = LICENSE
$(2)_SITE_METHOD = local
$(2)_SITE = $$(BR2_EXTERNAL_INFIX_PATH)/src/board/$(1)
$(2)_REDISTRIBUTE = NO
# The kernel must be built first.
$(2)_DEPENDENCIES += \
linux \
$$(BR2_MAKE_HOST_DEPENDENCY)
# This is only defined in some infrastructures (e.g. autotools, cmake),
# but not in others (e.g. generic). So define it here as well.
$(2)_MAKE ?= $$(BR2_MAKE)
define $(2)_DTBS_BUILD
@$$(call MESSAGE,"Building device tree blob(s)")
$$(LINUX_MAKE_ENV) $$($$(PKG)_MAKE) \
-C $$(LINUX_DIR) \
$$(LINUX_MAKE_FLAGS) \
$$($(2)_DTB_MAKE_OPTS) \
PWD=$$(@D)/dts \
M=$$(@D)/dts \
modules
endef
$(2)_POST_BUILD_HOOKS += $(2)_DTBS_BUILD
define $(2)_DTBS_INSTALL_TARGET
@$$(call MESSAGE,"Installing device tree blob(s)")
$$(TARGET_MAKE_ENV) $$(TARGET_CONFIGURE_OPTS) $$($$(PKG)_MAKE) \
-f $$(BR2_EXTERNAL_INFIX_PATH)/package/board/dtb-inst.makefile \
-C $$(@D)/dts \
DESTDIR="$$(TARGET_DIR)" \
install
endef
$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_DTBS_INSTALL_TARGET
define $(2)_OVERLAY_INSTALL_TARGET
@test -d $$(@D)/rootfs && \
$$(call MESSAGE,"Copying overlay") && \
$$(call SYSTEM_RSYNC,$$(@D)/rootfs,$(TARGET_DIR)) || \
true
endef
$(2)_POST_INSTALL_TARGET_HOOKS += $(2)_OVERLAY_INSTALL_TARGET
endef
ix-board = $(call inner-ix-board,$(pkgname),$(call UPPERCASE,$(pkgname)))
+39 -7
View File
@@ -35,13 +35,30 @@ define CONFD_INSTALL_EXTRA
cp $(CONFD_PKGDIR)/avahi.service $(TARGET_DIR)/etc/avahi/services/netconf.service
endef
NETOPEER2_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/netopeer2/
SYSREPO_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/sysrepo/
LIBNETCONF2_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/libnetconf2/
CONFD_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/confd/
TEST_MODE_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/test-mode/
ROUSETTE_SEARCHPATH=$(TARGET_DIR)/usr/share/yang/modules/rousette/
COMMON_SYSREPO_ENV = \
SYSREPO_SHM_PREFIX=$(CONFD_SYSREPO_SHM_PREFIX) \
SYSREPOCTL_EXECUTABLE="$(HOST_DIR)/bin/sysrepoctl" \
SYSREPOCFG_EXECUTABLE="$(HOST_DIR)/bin/sysrepocfg" \
SEARCH_PATH="$(TARGET_DIR)/usr/share/yang/modules/confd/"
SEARCH_PATH="$(NETOPEER2_SEARCHPATH) $(SYSREPO_SEARCHPATH) $(LIBNETCONF2_SEARCHPATH) $(TEST_MODE_SEARCHPATH) $(CONFD_SEARCHPATH) $(ROUSETTE_SEARCHPATH)"
define CONFD_INSTALL_YANG_MODULES
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/sysrepo.inc
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/libnetconf2.inc
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/netopeer2.inc
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/rousette.inc
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/test-mode.inc
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/confd.inc
endef
@@ -53,19 +70,34 @@ define CONFD_INSTALL_YANG_MODULES_CONTAINERS
endef
endif
define CONFD_PERMISSIONS
/etc/sysrepo/data/ r 660 root wheel - - - - -
/etc/sysrepo/data d 770 root wheel - - - - -
# PER_PACKAGE_DIR
# Since the last package in the dependency chain that runs sysrepoctl is confd, we need to
# manually copy the *real* content here from host-sysrepo.
ifeq ($(BR2_PER_PACKAGE_DIRECTORIES),y)
define CONFD_INSTALL_IN_ROMFS
cp -a $(PER_PACKAGE_DIR)/host-sysrepo/target/etc/sysrepo/* $(PER_PACKAGE_DIR)/confd/target/etc/sysrepo/
endef
endif
# PER_PACKAGE_DIR
# Need to do some special stuff if using per-packet (parallel) since sysrepo install the submodules in
# $(PER_PACKAGE_DIR)/host-sysrepo/target/etc/sysrepo/ but $(PER_PACKAGE_DIR)/confd/target/etc/sysrepo/ contains remains
# of other packets that have installed its models (netopeer2), we want the result in $(PER_PACKAGE_DIR)/host-sysrepo/target/etc/sysrepo/
define CONFD_EMPTY_SYSREPO
rm -rf $(TARGET_DIR)/etc/sysrepo/*
if [ "$(BR2_PER_PACKAGE_DIRECTORIES)" = "y" ]; then \
rm -rf $(PER_PACKAGE_DIR)/host-sysrepo/target/etc/sysrepo/* $(PER_PACKAGE_DIR)/confd/target/etc/sysrepo/*; \
fi
endef
define CONFD_CLEANUP
rm -f /dev/shm/$(CONFD_SYSREPO_SHM_PREFIX)*
endef
CONFD_PRE_INSTALL_TARGET_HOOKS += CONFD_CLEANUP
CONFD_PRE_BUILD_HOOKS += CONFD_EMPTY_SYSREPO
CONFD_PRE_BUILD_HOOKS += CONFD_CLEANUP
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_EXTRA
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_CONTAINERS
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_CLEANUP
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_IN_ROMFS
CONFD_TARGET_FINALIZE_HOOKS += CONFD_CLEANUP
$(eval $(autotools-package))
+1 -1
View File
@@ -1,5 +1,5 @@
# From https://github.com/troglobit/finit/releases/
sha256 7e49a3df58c5aedfff9537b7ff34b9238fc28b523d4dbacc316d606c7af5e335 finit-4.11.tar.gz
sha256 b6a0a2f98c860cf9fe5dfe7e3601d922957ad7880ae29919176ab960b7b96e70 finit-4.12.tar.gz
# Locally calculated
sha256 2fd62c0fe6ea6d1861669f4c87bda83a0b5ceca64f4baa4d16dd078fbd218c14 LICENSE
+1 -1
View File
@@ -4,7 +4,7 @@
#
################################################################################
FINIT_VERSION = 4.11
FINIT_VERSION = 4.12
FINIT_SITE = https://github.com/troglobit/finit/releases/download/$(FINIT_VERSION)
FINIT_LICENSE = MIT
FINIT_LICENSE_FILES = LICENSE
+1
View File
@@ -11,6 +11,7 @@ LANDING_LICENSE = ISC
LANDING_LICENSE_FILES = LICENSE
define LANDING_INSTALL_TARGET_CMDS
mkdir -p $(TARGET_DIR)/usr/html/
cp $(@D)/*.html $(TARGET_DIR)/usr/html/
cp $(@D)/*.png $(TARGET_DIR)/usr/html/
endef
@@ -1,11 +1,11 @@
From d0f6422fee7a46fcb7445c88f499f61b3eb0ead0 Mon Sep 17 00:00:00 2001
From: Adam Piecek <Adam.Piecek@cesnet.cz>
Date: Wed, 23 Oct 2024 14:37:09 +0200
Subject: [PATCH 1/8] added support for RpcYang in Context::parseOp
Subject: [PATCH 01/18] added support for RpcYang in Context::parseOp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Change-Id: I25182ea2d042be1e6e4246e18aee260cc032e547
Signed-off-by: Mattias Walström <lazzer@gmail.com>
@@ -1,11 +1,11 @@
From 7e015f3486bdbb54f1dcc2e2ce51102b1d623081 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 23 Oct 2024 12:52:24 +0200
Subject: [PATCH 2/8] throw when lyd_validate_all returns error
Subject: [PATCH 02/18] throw when lyd_validate_all returns error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Bug: https://github.com/CESNET/libyang-cpp/issues/20
Change-Id: I005a2f1b057978573a4046e7b4cc31d77e36fde3
@@ -1,11 +1,11 @@
From 490d8bb242d33213b948485f5b94c55e22cf86a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Thu, 21 Nov 2024 11:32:44 +0100
Subject: [PATCH 3/8] remove a misleading comment
Subject: [PATCH 03/18] remove a misleading comment
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
The whole intention within action's input/output handling here was to
put some emphasis on the fact that we aren't tracking the input/output
@@ -1,11 +1,11 @@
From e1b17386cf61048d2fe27fffb3b763981a225f52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bed=C5=99ich=20Schindler?= <bedrich.schindler@gmail.com>
Date: Wed, 27 Nov 2024 09:47:47 +0100
Subject: [PATCH 4/8] schema: improve `List::keys()` not to use `std::move`
Subject: [PATCH 04/18] schema: improve `List::keys()` not to use `std::move`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
`List::keys()` used `std::move` while iterating over array of leafs.
This was solved without using `std::move`.
@@ -1,11 +1,11 @@
From 1102ecdcafbc9206f59b383769687e418557838e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bed=C5=99ich=20Schindler?= <bedrich.schindler@gmail.com>
Date: Mon, 25 Nov 2024 15:54:02 +0100
Subject: [PATCH 5/8] schema: make leaf-list's `default` statement available
Subject: [PATCH 05/18] schema: make leaf-list's `default` statement available
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Make leaf-list's `default` statement available so that it can be
accessed if end-user requires reading schema nodes.
@@ -1,11 +1,11 @@
From 01f2633cef60495d5cafc4b4b1f25273b03ab3cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bed=C5=99ich=20Schindler?= <bedrich.schindler@gmail.com>
Date: Tue, 22 Oct 2024 15:11:30 +0200
Subject: [PATCH 6/8] schema: Make choice and case statements available
Subject: [PATCH 06/18] schema: Make choice and case statements available
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Make choice and case statements available so that they can be accessed
if end-user requires reading schema nodes.
@@ -1,12 +1,12 @@
From a1acdc794facf8cbf113f73274ecebd5898c81a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Tue, 17 Dec 2024 15:08:43 +0100
Subject: [PATCH 7/8] Wrap lyd_change_term for changing the value for a
Subject: [PATCH 07/18] Wrap lyd_change_term for changing the value for a
terminal node
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Previously, the code would require a newPath(...,
libyang::CreationOptions::Update), which is quite a mouthful.
@@ -0,0 +1,652 @@
From 32b200ed06e9adb44a8d4ce6771f18812a54d06e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bed=C5=99ich=20Schindler?= <bedrich.schindler@gmail.com>
Date: Wed, 20 Nov 2024 10:20:19 +0100
Subject: [PATCH 08/18] Add `Module::child()`, `Module::childrenDfs()` and
`Module::immediateChildren()`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Those functions are implemented in the same manner as in `SchemaNode`
and allows to walk through modules children. This is counterpart to
already implemented `Module::childInstantiables()` that returns
instantiables schema nodes. These return all nodes, including
the schema-only nodes such as choice and case if end-user needs
to read its schema.
While the implementation is inspired by functions in `SchemaNode`,
imlementation of `Module::parent()` and `Module::siblings()` was omitted
as those do no make sense on `Module`.
Change-Id: I38c8374304f859d65343d04d08302e07deb05f27
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
include/libyang-cpp/Collection.hpp | 1 +
include/libyang-cpp/Module.hpp | 5 +
src/Module.cpp | 40 +++
tests/context.cpp | 5 +
tests/example_schema.hpp | 21 ++
tests/schema_node.cpp | 409 +++++++++++++++++++----------
6 files changed, 346 insertions(+), 135 deletions(-)
diff --git a/include/libyang-cpp/Collection.hpp b/include/libyang-cpp/Collection.hpp
index 557a0a2..4324791 100644
--- a/include/libyang-cpp/Collection.hpp
+++ b/include/libyang-cpp/Collection.hpp
@@ -98,6 +98,7 @@ class LIBYANG_CPP_EXPORT Collection {
public:
friend DataNode;
friend Iterator<NodeType, ITER_TYPE>;
+ friend Module;
friend SchemaNode;
~Collection();
Collection(const Collection<NodeType, ITER_TYPE>&);
diff --git a/include/libyang-cpp/Module.hpp b/include/libyang-cpp/Module.hpp
index f10c36f..ab20d36 100644
--- a/include/libyang-cpp/Module.hpp
+++ b/include/libyang-cpp/Module.hpp
@@ -34,6 +34,8 @@ class ChildInstanstiables;
class Identity;
class SchemaNode;
class SubmoduleParsed;
+template <typename NodeType, IterationType ITER_TYPE>
+class Collection;
namespace types {
class IdentityRef;
@@ -86,7 +88,10 @@ public:
std::vector<Identity> identities() const;
+ std::optional<SchemaNode> child() const;
ChildInstanstiables childInstantiables() const;
+ libyang::Collection<SchemaNode, IterationType::Dfs> childrenDfs() const;
+ Collection<SchemaNode, IterationType::Sibling> immediateChildren() const;
std::vector<SchemaNode> actionRpcs() const;
std::string printStr(const SchemaOutputFormat format, const std::optional<SchemaPrintFlags> flags = std::nullopt, std::optional<size_t> lineLength = std::nullopt) const;
diff --git a/src/Module.cpp b/src/Module.cpp
index 4dc9e3b..d6d4023 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -8,6 +8,7 @@
#include <algorithm>
#include <libyang-cpp/ChildInstantiables.hpp>
+#include <libyang-cpp/Collection.hpp>
#include <libyang-cpp/Module.hpp>
#include <libyang-cpp/Utils.hpp>
#include <libyang/libyang.h>
@@ -178,6 +179,23 @@ std::vector<Identity> Module::identities() const
return res;
}
+/**
+ * @brief Returns the first child node of this module.
+ * @return The child, or std::nullopt if there are no children.
+ */
+std::optional<SchemaNode> Module::child() const
+{
+ if (!m_module->implemented) {
+ throw Error{"Module::child: module is not implemented"};
+ }
+
+ if (!m_module->compiled->data) {
+ return std::nullopt;
+ }
+
+ return SchemaNode{m_module->compiled->data, m_ctx};
+}
+
/**
* @brief Returns a collection of data instantiable top-level nodes of this module.
*
@@ -191,6 +209,28 @@ ChildInstanstiables Module::childInstantiables() const
return ChildInstanstiables{nullptr, m_module->compiled, m_ctx};
}
+/**
+ * @brief Returns a collection for iterating depth-first over the subtree this module points to.
+ */
+Collection<SchemaNode, IterationType::Dfs> Module::childrenDfs() const
+{
+ if (!m_module->implemented) {
+ throw Error{"Module::childrenDfs: module is not implemented"};
+ }
+ return Collection<SchemaNode, IterationType::Dfs>{m_module->compiled->data, m_ctx};
+}
+
+/**
+ * @brief Returns a collection for iterating over the immediate children of where this module points to.
+ *
+ * This is a convenience function for iterating over this->child().siblings() which does not throw even when module has no children.
+ */
+Collection<SchemaNode, IterationType::Sibling> Module::immediateChildren() const
+{
+ auto c = child();
+ return c ? c->siblings() : Collection<SchemaNode, IterationType::Sibling>{nullptr, nullptr};
+}
+
/**
* @brief Returns a collection of RPC nodes (not action nodes) as SchemaNode
*
diff --git a/tests/context.cpp b/tests/context.cpp
index 5929b75..25343db 100644
--- a/tests/context.cpp
+++ b/tests/context.cpp
@@ -713,6 +713,11 @@ TEST_CASE("context")
+--rw anydataWithMandatoryChild anydata
+--rw anyxmlBasic? anyxml
+--rw anyxmlWithMandatoryChild anyxml
+ +--rw (choiceOnModule)?
+ | +--:(case1)
+ | | +--rw choiceOnModuleLeaf1? string
+ | +--:(case2)
+ | +--rw choiceOnModuleLeaf2? string
+--rw choiceBasicContainer
| +--rw (choiceBasic)?
| +--:(case1)
diff --git a/tests/example_schema.hpp b/tests/example_schema.hpp
index ae3b4de..0d8acb9 100644
--- a/tests/example_schema.hpp
+++ b/tests/example_schema.hpp
@@ -390,6 +390,19 @@ module type_module {
mandatory true;
}
+ choice choiceOnModule {
+ case case1 {
+ leaf choiceOnModuleLeaf1 {
+ type string;
+ }
+ }
+ case case2 {
+ leaf choiceOnModuleLeaf2 {
+ type string;
+ }
+ }
+ }
+
container choiceBasicContainer {
choice choiceBasic {
case case1 {
@@ -787,6 +800,14 @@ module type_module {
}
)"s;
+const auto empty_module = R"(
+module empty_module {
+ yang-version 1.1;
+ namespace "e";
+ prefix "e";
+}
+)"s;
+
const auto with_inet_types_module = R"(
module with-inet-types {
yang-version 1.1;
diff --git a/tests/schema_node.cpp b/tests/schema_node.cpp
index 8d74bd2..0001377 100644
--- a/tests/schema_node.cpp
+++ b/tests/schema_node.cpp
@@ -24,8 +24,10 @@ TEST_CASE("SchemaNode")
libyang::ContextOptions::SetPrivParsed | libyang::ContextOptions::NoYangLibrary | libyang::ContextOptions::DisableSearchCwd};
ctx->parseModule(example_schema, libyang::SchemaFormat::YANG);
ctx->parseModule(type_module, libyang::SchemaFormat::YANG);
+ ctx->parseModule(empty_module, libyang::SchemaFormat::YANG);
ctxWithParsed->parseModule(example_schema, libyang::SchemaFormat::YANG);
ctxWithParsed->parseModule(type_module, libyang::SchemaFormat::YANG);
+ ctxWithParsed->parseModule(empty_module, libyang::SchemaFormat::YANG);
DOCTEST_SUBCASE("context lifetime")
{
@@ -74,10 +76,34 @@ TEST_CASE("SchemaNode")
REQUIRE(node->schema().path() == "/example-schema:person");
}
- DOCTEST_SUBCASE("SchemaNode::child")
+ DOCTEST_SUBCASE("child")
{
- REQUIRE(ctx->findPath("/type_module:listAdvancedWithTwoKey").child()->name() == "first");
- REQUIRE(!ctx->findPath("/type_module:leafString").child().has_value());
+ DOCTEST_SUBCASE("implemented module")
+ {
+ DOCTEST_SUBCASE("SchemaNode::child")
+ {
+ REQUIRE(ctx->findPath("/type_module:listAdvancedWithTwoKey").child()->name() == "first");
+ REQUIRE(!ctx->findPath("/type_module:leafString").child().has_value());
+ }
+
+ DOCTEST_SUBCASE("Module::child")
+ {
+ REQUIRE(ctx->getModule("type_module", std::nullopt)->child()->name() == "anydataBasic");
+ REQUIRE(!ctx->getModule("empty_module", std::nullopt)->child());
+ }
+ }
+
+ DOCTEST_SUBCASE("unimplemented module")
+ {
+ DOCTEST_SUBCASE("Module::child")
+ {
+ ctx->setSearchDir(TESTS_DIR / "yang");
+ auto modYangPatch = ctx->loadModule("ietf-yang-patch", std::nullopt);
+ auto modRestconf = ctx->getModule("ietf-restconf", "2017-01-26");
+ REQUIRE(!modRestconf->implemented());
+ REQUIRE_THROWS_WITH_AS(modRestconf->child(), "Module::child: module is not implemented", libyang::Error);
+ }
+ }
}
DOCTEST_SUBCASE("SchemaNode::config")
@@ -160,162 +186,275 @@ TEST_CASE("SchemaNode")
DOCTEST_SUBCASE("childInstantiables")
{
- std::vector<std::string> expectedPaths;
- std::optional<libyang::ChildInstanstiables> children;
-
- DOCTEST_SUBCASE("SchemaNode::childInstantiables")
+ DOCTEST_SUBCASE("implemented module")
{
- expectedPaths = {
- "/type_module:listAdvancedWithOneKey/lol",
- "/type_module:listAdvancedWithOneKey/notKey1",
- "/type_module:listAdvancedWithOneKey/notKey2",
- "/type_module:listAdvancedWithOneKey/notKey3",
- "/type_module:listAdvancedWithOneKey/notKey4",
- };
+ std::vector<std::string> expectedPaths;
+ std::optional<libyang::ChildInstanstiables> children;
+
+ DOCTEST_SUBCASE("SchemaNode::childInstantiables")
+ {
+ expectedPaths = {
+ "/type_module:listAdvancedWithOneKey/lol",
+ "/type_module:listAdvancedWithOneKey/notKey1",
+ "/type_module:listAdvancedWithOneKey/notKey2",
+ "/type_module:listAdvancedWithOneKey/notKey3",
+ "/type_module:listAdvancedWithOneKey/notKey4",
+ };
+
+ children = ctx->findPath("/type_module:listAdvancedWithOneKey").childInstantiables();
+ }
- children = ctx->findPath("/type_module:listAdvancedWithOneKey").childInstantiables();
- }
+ DOCTEST_SUBCASE("Module::childInstantiables")
+ {
+ expectedPaths = {
+ "/type_module:anydataBasic",
+ "/type_module:anydataWithMandatoryChild",
+ "/type_module:anyxmlBasic",
+ "/type_module:anyxmlWithMandatoryChild",
+ "/type_module:choiceOnModuleLeaf1",
+ "/type_module:choiceOnModuleLeaf2",
+ "/type_module:choiceBasicContainer",
+ "/type_module:choiceWithMandatoryContainer",
+ "/type_module:choiceWithDefaultContainer",
+ "/type_module:implicitCaseContainer",
+ "/type_module:leafBinary",
+ "/type_module:leafBits",
+ "/type_module:leafEnum",
+ "/type_module:leafEnum2",
+ "/type_module:leafNumber",
+ "/type_module:leafRef",
+ "/type_module:leafRefRelaxed",
+ "/type_module:leafString",
+ "/type_module:leafUnion",
+ "/type_module:meal",
+ "/type_module:leafWithConfigFalse",
+ "/type_module:leafWithDefaultValue",
+ "/type_module:leafWithDescription",
+ "/type_module:leafWithMandatoryTrue",
+ "/type_module:leafWithStatusDeprecated",
+ "/type_module:leafWithStatusObsolete",
+ "/type_module:leafWithUnits",
+ "/type_module:iid-valid",
+ "/type_module:iid-relaxed",
+ "/type_module:leafListBasic",
+ "/type_module:leafListWithDefault",
+ "/type_module:leafListWithMinMaxElements",
+ "/type_module:leafListWithUnits",
+ "/type_module:listBasic",
+ "/type_module:listAdvancedWithOneKey",
+ "/type_module:listAdvancedWithTwoKey",
+ "/type_module:listWithMinMaxElements",
+ "/type_module:numeric",
+ "/type_module:container",
+ "/type_module:containerWithMandatoryChild",
+ };
+ children = ctx->getModule("type_module", std::nullopt)->childInstantiables();
+ }
- DOCTEST_SUBCASE("Module::childInstantiables")
- {
- expectedPaths = {
- "/type_module:anydataBasic",
- "/type_module:anydataWithMandatoryChild",
- "/type_module:anyxmlBasic",
- "/type_module:anyxmlWithMandatoryChild",
- "/type_module:choiceBasicContainer",
- "/type_module:choiceWithMandatoryContainer",
- "/type_module:choiceWithDefaultContainer",
- "/type_module:implicitCaseContainer",
- "/type_module:leafBinary",
- "/type_module:leafBits",
- "/type_module:leafEnum",
- "/type_module:leafEnum2",
- "/type_module:leafNumber",
- "/type_module:leafRef",
- "/type_module:leafRefRelaxed",
- "/type_module:leafString",
- "/type_module:leafUnion",
- "/type_module:meal",
- "/type_module:leafWithConfigFalse",
- "/type_module:leafWithDefaultValue",
- "/type_module:leafWithDescription",
- "/type_module:leafWithMandatoryTrue",
- "/type_module:leafWithStatusDeprecated",
- "/type_module:leafWithStatusObsolete",
- "/type_module:leafWithUnits",
- "/type_module:iid-valid",
- "/type_module:iid-relaxed",
- "/type_module:leafListBasic",
- "/type_module:leafListWithDefault",
- "/type_module:leafListWithMinMaxElements",
- "/type_module:leafListWithUnits",
- "/type_module:listBasic",
- "/type_module:listAdvancedWithOneKey",
- "/type_module:listAdvancedWithTwoKey",
- "/type_module:listWithMinMaxElements",
- "/type_module:numeric",
- "/type_module:container",
- "/type_module:containerWithMandatoryChild",
- };
- children = ctx->getModule("type_module", std::nullopt)->childInstantiables();
- }
+ std::vector<std::string> actualPaths;
+ for (const auto& child : *children) {
+ actualPaths.emplace_back(child.path());
+ }
- std::vector<std::string> actualPaths;
- for (const auto& child : *children) {
- actualPaths.emplace_back(child.path());
+ REQUIRE(expectedPaths == actualPaths);
}
- REQUIRE(expectedPaths == actualPaths);
+ DOCTEST_SUBCASE("unimplemented module")
+ {
+ DOCTEST_SUBCASE("Module::childInstantiables")
+ {
+ ctx->setSearchDir(TESTS_DIR / "yang");
+ auto modYangPatch = ctx->loadModule("ietf-yang-patch", std::nullopt);
+ auto modRestconf = ctx->getModule("ietf-restconf", "2017-01-26");
+ REQUIRE(!modRestconf->implemented());
+ REQUIRE_THROWS_WITH_AS(modRestconf->childInstantiables(), "Module::childInstantiables: module is not implemented", libyang::Error);
+ }
+ }
}
- DOCTEST_SUBCASE("SchemaNode::childrenDfs")
+ DOCTEST_SUBCASE("childrenDfs")
{
- std::vector<std::string> expectedPaths;
+ DOCTEST_SUBCASE("implemented module")
+ {
+ std::vector<std::string> expectedPaths;
+ std::optional<libyang::Collection<libyang::SchemaNode, libyang::IterationType::Dfs>> children;
- const char* path;
+ DOCTEST_SUBCASE("SchemaNode::childrenDfs")
+ {
+ DOCTEST_SUBCASE("listAdvancedWithTwoKey")
+ {
+ expectedPaths = {
+ "/type_module:listAdvancedWithTwoKey",
+ "/type_module:listAdvancedWithTwoKey/first",
+ "/type_module:listAdvancedWithTwoKey/second",
+ };
+ children = ctx->findPath("/type_module:listAdvancedWithTwoKey").childrenDfs();
+ }
- DOCTEST_SUBCASE("listAdvancedWithTwoKey")
- {
- expectedPaths = {
- "/type_module:listAdvancedWithTwoKey",
- "/type_module:listAdvancedWithTwoKey/first",
- "/type_module:listAdvancedWithTwoKey/second",
- };
+ DOCTEST_SUBCASE("DFS on a leaf")
+ {
+ expectedPaths = {
+ "/type_module:leafString",
+ };
+ children = ctx->findPath("/type_module:leafString").childrenDfs();
+ }
+ }
- path = "/type_module:listAdvancedWithTwoKey";
- }
+ DOCTEST_SUBCASE("Module::childrenDfs")
+ {
+ expectedPaths = {
+ "/type_module:anydataBasic",
+ };
+ children = ctx->getModule("type_module", std::nullopt)->childrenDfs();
+ }
- DOCTEST_SUBCASE("DFS on a leaf")
- {
- expectedPaths = {
- "/type_module:leafString",
- };
+ std::vector<std::string> actualPaths;
+ for (const auto& it : *children) {
+ actualPaths.emplace_back(it.path());
+ }
- path = "/type_module:leafString";
+ REQUIRE(actualPaths == expectedPaths);
}
- std::vector<std::string> actualPaths;
- for (const auto& it : ctx->findPath(path).childrenDfs()) {
- actualPaths.emplace_back(it.path());
+ DOCTEST_SUBCASE("unimplemented module")
+ {
+ DOCTEST_SUBCASE("Module::childrenDfs")
+ {
+ ctx->setSearchDir(TESTS_DIR / "yang");
+ auto modYangPatch = ctx->loadModule("ietf-yang-patch", std::nullopt);
+ auto modRestconf = ctx->getModule("ietf-restconf", "2017-01-26");
+ REQUIRE(!modRestconf->implemented());
+ REQUIRE_THROWS_WITH_AS(modRestconf->childrenDfs(), "Module::childrenDfs: module is not implemented", libyang::Error);
+ }
}
-
- REQUIRE(actualPaths == expectedPaths);
}
- DOCTEST_SUBCASE("SchemaNode::immediateChildren")
+ DOCTEST_SUBCASE("immediateChildren")
{
- std::vector<std::string> expectedPaths;
- const char* path;
- DOCTEST_SUBCASE("listAdvancedWithTwoKey")
- {
- expectedPaths = {
- "/type_module:listAdvancedWithTwoKey/first",
- "/type_module:listAdvancedWithTwoKey/second",
- };
- path = "/type_module:listAdvancedWithTwoKey";
- }
- DOCTEST_SUBCASE("leaf")
+ DOCTEST_SUBCASE("implemented module")
{
- expectedPaths = {
- };
- path = "/type_module:leafString";
- }
- DOCTEST_SUBCASE("no recursion")
- {
- expectedPaths = {
- "/type_module:container/x",
- "/type_module:container/y",
- "/type_module:container/z",
- };
- path = "/type_module:container";
- }
- DOCTEST_SUBCASE("empty container")
- {
- expectedPaths = {
- };
- path = "/type_module:container/y";
- }
- DOCTEST_SUBCASE("one item")
- {
- expectedPaths = {
- "/type_module:container/z/z1",
- };
- path = "/type_module:container/z";
+ std::vector<std::string> expectedPaths;
+ std::optional<libyang::Collection<libyang::SchemaNode, libyang::IterationType::Sibling>> children;
+
+ DOCTEST_SUBCASE("SchemaNode::immediateChildren")
+ {
+ DOCTEST_SUBCASE("listAdvancedWithTwoKey")
+ {
+ expectedPaths = {
+ "/type_module:listAdvancedWithTwoKey/first",
+ "/type_module:listAdvancedWithTwoKey/second",
+ };
+ children = ctx->findPath("/type_module:listAdvancedWithTwoKey").immediateChildren();
+ }
+ DOCTEST_SUBCASE("leaf")
+ {
+ expectedPaths = {};
+ children = ctx->findPath("/type_module:leafString").immediateChildren();
+ }
+ DOCTEST_SUBCASE("no recursion")
+ {
+ expectedPaths = {
+ "/type_module:container/x",
+ "/type_module:container/y",
+ "/type_module:container/z",
+ };
+ children = ctx->findPath("/type_module:container").immediateChildren();
+ }
+ DOCTEST_SUBCASE("empty container")
+ {
+ expectedPaths = {};
+ children = ctx->findPath("/type_module:container/y").immediateChildren();
+ }
+ DOCTEST_SUBCASE("one item")
+ {
+ expectedPaths = {
+ "/type_module:container/z/z1",
+ };
+ children = ctx->findPath("/type_module:container/z").immediateChildren();
+ }
+ DOCTEST_SUBCASE("two items")
+ {
+ expectedPaths = {
+ "/type_module:container/x/x1",
+ "/type_module:container/x/x2",
+ };
+ children = ctx->findPath("/type_module:container/x").immediateChildren();
+ }
+ }
+
+ DOCTEST_SUBCASE("Module::immediateChildren")
+ {
+ expectedPaths = {
+ "/type_module:anydataBasic",
+ "/type_module:anydataWithMandatoryChild",
+ "/type_module:anyxmlBasic",
+ "/type_module:anyxmlWithMandatoryChild",
+ // choiceOnModule is a choice, so it doesn't have path "/type_module:choiceOnModule".
+ // This node is tested at the end of the test subcase.
+ "/",
+ "/type_module:choiceBasicContainer",
+ "/type_module:choiceWithMandatoryContainer",
+ "/type_module:choiceWithDefaultContainer",
+ "/type_module:implicitCaseContainer",
+ "/type_module:leafBinary",
+ "/type_module:leafBits",
+ "/type_module:leafEnum",
+ "/type_module:leafEnum2",
+ "/type_module:leafNumber",
+ "/type_module:leafRef",
+ "/type_module:leafRefRelaxed",
+ "/type_module:leafString",
+ "/type_module:leafUnion",
+ "/type_module:meal",
+ "/type_module:leafWithConfigFalse",
+ "/type_module:leafWithDefaultValue",
+ "/type_module:leafWithDescription",
+ "/type_module:leafWithMandatoryTrue",
+ "/type_module:leafWithStatusDeprecated",
+ "/type_module:leafWithStatusObsolete",
+ "/type_module:leafWithUnits",
+ "/type_module:iid-valid",
+ "/type_module:iid-relaxed",
+ "/type_module:leafListBasic",
+ "/type_module:leafListWithDefault",
+ "/type_module:leafListWithMinMaxElements",
+ "/type_module:leafListWithUnits",
+ "/type_module:listBasic",
+ "/type_module:listAdvancedWithOneKey",
+ "/type_module:listAdvancedWithTwoKey",
+ "/type_module:listWithMinMaxElements",
+ "/type_module:numeric",
+ "/type_module:container",
+ "/type_module:containerWithMandatoryChild",
+ };
+ children = ctx->getModule("type_module", std::nullopt)->immediateChildren();
+
+ std::vector<std::string> actualNames;
+ for (auto it : children.value()) {
+ actualNames.emplace_back(it.name());
+ }
+ // choiceOnModule is a choice, so it doesn't have path, just name.
+ REQUIRE(actualNames[4] == "choiceOnModule");
+ }
+
+ std::vector<std::string> actualPaths;
+ for (const auto& it : *children) {
+ actualPaths.emplace_back(it.path());
+ }
+ REQUIRE(actualPaths == expectedPaths);
}
- DOCTEST_SUBCASE("two items")
+
+ DOCTEST_SUBCASE("unimplemented module")
{
- expectedPaths = {
- "/type_module:container/x/x1",
- "/type_module:container/x/x2",
- };
- path = "/type_module:container/x";
- }
- std::vector<std::string> actualPaths;
- for (const auto& it : ctx->findPath(path).immediateChildren()) {
- actualPaths.emplace_back(it.path());
+ DOCTEST_SUBCASE("Module::immediateChildren")
+ {
+ ctx->setSearchDir(TESTS_DIR / "yang");
+ auto modYangPatch = ctx->loadModule("ietf-yang-patch", std::nullopt);
+ auto modRestconf = ctx->getModule("ietf-restconf", "2017-01-26");
+ REQUIRE(!modRestconf->implemented());
+ REQUIRE_THROWS_WITH_AS(modRestconf->immediateChildren(), "Module::child: module is not implemented", libyang::Error);
+ }
}
- REQUIRE(actualPaths == expectedPaths);
}
DOCTEST_SUBCASE("SchemaNode::siblings")
--
2.43.0
@@ -1,11 +1,11 @@
From 39c7530caa510144c17521278b721ba1e6d8ff40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Thu, 9 Jan 2025 15:31:37 +0100
Subject: [PATCH 8/8] upstream stopped reporting schema-mounts node
Subject: [PATCH 09/18] upstream stopped reporting schema-mounts node
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Change-Id: I940769d38d56fcfda3e1408c92331fdb00c161e9
Signed-off-by: Mattias Walström <lazzer@gmail.com>
@@ -0,0 +1,39 @@
From 82c963766ad4e4a802db7be656acbedb640745e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Thu, 30 Jan 2025 16:34:12 +0100
Subject: [PATCH 10/18] CI: temporarily pin version due to anyxml behavior
changes upstream
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: Id977f4d045098c1b93656c0efb871c9a1b650e2d
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
.zuul.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.zuul.yaml b/.zuul.yaml
index b41c490..19f0def 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -4,13 +4,13 @@
- f38-gcc-cover:
required-projects:
- name: github/CESNET/libyang
- override-checkout: devel
+ override-checkout: cesnet/2025-01-29
- name: github/onqtam/doctest
override-checkout: v2.3.6
- f38-clang-asan-ubsan:
required-projects: &projects
- name: github/CESNET/libyang
- override-checkout: devel
+ override-checkout: cesnet/2025-01-29
- name: github/onqtam/doctest
override-checkout: v2.4.11
- f38-clang-tsan:
--
2.43.0
@@ -0,0 +1,40 @@
From 50a216e35a555961f94a32a71bb2d45ac611d0aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Wed, 29 Jan 2025 22:49:08 +0100
Subject: [PATCH 11/18] build: a single place to define package version
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: I2cd7397895ed4852f852e99b97543dde76eaff8f
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 732f52b..c518ca8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,7 +21,8 @@ add_custom_target(libyang-cpp-version-cmake
cmake/ProjectGitVersionRunner.cmake
)
include(cmake/ProjectGitVersion.cmake)
-prepare_git_version(LIBYANG_CPP_VERSION "3")
+set(LIBYANG_CPP_PKG_VERSION "3")
+prepare_git_version(LIBYANG_CPP_VERSION ${LIBYANG_CPP_PKG_VERSION})
find_package(Doxygen)
option(WITH_DOCS "Create and install internal documentation (needs Doxygen)" ${DOXYGEN_FOUND})
@@ -29,7 +30,6 @@ option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a st
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBYANG REQUIRED libyang>=3.7.8 IMPORTED_TARGET)
-set(LIBYANG_CPP_PKG_VERSION "3")
# FIXME from gcc 14.1 on we should be able to use the calendar/time from libstdc++ and thus remove the date dependency
find_package(date)
--
2.43.0
@@ -0,0 +1,173 @@
From 1533458346b4f395b1187c646b61bbcb1fddc615 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Mon, 4 Nov 2024 14:52:12 +0100
Subject: [PATCH 12/18] YANG-flavored regular expressions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: I93b2756d0f470585280c076308df3f384bd7765d
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 3 +++
include/libyang-cpp/Regex.hpp | 28 ++++++++++++++++++++++
src/Regex.cpp | 45 +++++++++++++++++++++++++++++++++++
tests/regex.cpp | 30 +++++++++++++++++++++++
4 files changed, 106 insertions(+)
create mode 100644 include/libyang-cpp/Regex.hpp
create mode 100644 src/Regex.cpp
create mode 100644 tests/regex.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c518ca8..512af8c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,6 +54,7 @@ add_library(yang-cpp
src/Enum.cpp
src/Collection.cpp
src/Module.cpp
+ src/Regex.cpp
src/SchemaNode.cpp
src/Set.cpp
src/Type.cpp
@@ -83,6 +84,7 @@ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24")
libyang-cpp/Enum.hpp
libyang-cpp/ChildInstantiables.hpp
libyang-cpp/Module.hpp
+ libyang-cpp/Regex.hpp
libyang-cpp/Set.hpp
libyang-cpp/SchemaNode.hpp
libyang-cpp/Time.hpp
@@ -119,6 +121,7 @@ if(BUILD_TESTING)
libyang_cpp_test(schema_node)
libyang_cpp_test(unsafe)
target_link_libraries(test_unsafe PkgConfig::LIBYANG)
+ libyang_cpp_test(regex)
if(date_FOUND)
add_executable(test_time-stl-hhdate tests/time.cpp)
diff --git a/include/libyang-cpp/Regex.hpp b/include/libyang-cpp/Regex.hpp
new file mode 100644
index 0000000..31935f2
--- /dev/null
+++ b/include/libyang-cpp/Regex.hpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#pragma once
+#include <libyang-cpp/export.h>
+#include <string>
+
+namespace libyang {
+class Context;
+
+/**
+ * @brief A regular expression pattern which uses the YANG-flavored regex engine
+ */
+class LIBYANG_CPP_EXPORT Regex {
+public:
+ Regex(const std::string& pattern);
+ ~Regex();
+ bool matches(const std::string& input);
+
+private:
+ void* code;
+};
+
+}
diff --git a/src/Regex.cpp b/src/Regex.cpp
new file mode 100644
index 0000000..a34fcd5
--- /dev/null
+++ b/src/Regex.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// The following header MUST be included before anything else which "might" use PCRE2
+// because that library uses the preprocessor to prepare the "correct" versions of symbols.
+#include <libyang/tree_data.h>
+
+#include <libyang-cpp/Regex.hpp>
+#include <pcre2.h>
+#include "utils/exception.hpp"
+
+#define THE_PCRE2_CODE_P reinterpret_cast<pcre2_code*>(this->code)
+#define THE_PCRE2_CODE_P_P reinterpret_cast<pcre2_code**>(&this->code)
+
+namespace libyang {
+
+Regex::Regex(const std::string& pattern)
+ : code(nullptr)
+{
+ auto res = ly_pattern_compile(nullptr, pattern.c_str(), THE_PCRE2_CODE_P_P);
+ throwIfError(res, ly_last_logmsg());
+}
+
+Regex::~Regex()
+{
+ pcre2_code_free(THE_PCRE2_CODE_P);
+}
+
+bool Regex::matches(const std::string& input)
+{
+ auto res = ly_pattern_match(nullptr, nullptr /* we have a precompiled pattern */, input.c_str(), input.size(), THE_PCRE2_CODE_P_P);
+ if (res == LY_SUCCESS) {
+ return true;
+ } else if (res == LY_ENOT) {
+ return false;
+ } else {
+ throwError(res, ly_last_logmsg());
+ }
+}
+}
diff --git a/tests/regex.cpp b/tests/regex.cpp
new file mode 100644
index 0000000..7594f43
--- /dev/null
+++ b/tests/regex.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2025 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <doctest/doctest.h>
+#include <libyang-cpp/Regex.hpp>
+#include <libyang-cpp/Utils.hpp>
+
+TEST_CASE("regex")
+{
+ using libyang::Regex;
+ using namespace std::string_literals;
+
+ REQUIRE_THROWS_WITH_AS(Regex{"\\"}, R"(Regular expression "\" is not valid ("": \ at end of pattern).: LY_EVALID)", libyang::ErrorWithCode);
+
+ Regex re{"ahoj"};
+ REQUIRE(re.matches("ahoj"));
+ REQUIRE(!re.matches("cau"));
+ REQUIRE(re.matches("ahoj")); // test repeated calls as well
+ REQUIRE(!re.matches("oj"));
+ REQUIRE(!re.matches("aho"));
+
+ // Testing runtime errors during pattern *matching* is tricky. There's a limit on backtracking,
+ // so testing a pattern like x+x+y on an obscenely long string of "x" characters *will* do the trick, eventually,
+ // but the PCRE2 library has a default limit of 10M attempts. That's a VERY big number to hit during a test :(.
+}
--
2.43.0
@@ -0,0 +1,67 @@
From 8d406728a53c2e77a4fe7393b7e30d42b8f9b9bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Thu, 30 Jan 2025 15:40:22 +0100
Subject: [PATCH 13/18] Adapt to upstream changes in anyxml JSON printing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: I5f6de28cebc95a446549017c2768b450f4fd6526
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
.zuul.yaml | 4 ++--
CMakeLists.txt | 3 ++-
tests/data_node.cpp | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/.zuul.yaml b/.zuul.yaml
index 19f0def..b41c490 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -4,13 +4,13 @@
- f38-gcc-cover:
required-projects:
- name: github/CESNET/libyang
- override-checkout: cesnet/2025-01-29
+ override-checkout: devel
- name: github/onqtam/doctest
override-checkout: v2.3.6
- f38-clang-asan-ubsan:
required-projects: &projects
- name: github/CESNET/libyang
- override-checkout: cesnet/2025-01-29
+ override-checkout: devel
- name: github/onqtam/doctest
override-checkout: v2.4.11
- f38-clang-tsan:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 512af8c..a40fd52 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,7 +29,8 @@ option(WITH_DOCS "Create and install internal documentation (needs Doxygen)" ${D
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(LIBYANG REQUIRED libyang>=3.7.8 IMPORTED_TARGET)
+# FIXME: it's actually 3.7.12, but that hasn't been released yet
+pkg_check_modules(LIBYANG REQUIRED libyang>=3.7.11 IMPORTED_TARGET)
# FIXME from gcc 14.1 on we should be able to use the calendar/time from libstdc++ and thus remove the date dependency
find_package(date)
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
index 45fd6c1..14470dd 100644
--- a/tests/data_node.cpp
+++ b/tests/data_node.cpp
@@ -1568,7 +1568,7 @@ TEST_CASE("Data Node manipulation")
REQUIRE(*jsonAnyXmlNode.createdNode->printStr(libyang::DataFormat::JSON, libyang::PrintFlags::Shrink | libyang::PrintFlags::WithSiblings)
== R"|({"example-schema:ax":[1,2,3]})|"s);
REQUIRE(*jsonAnyXmlNode.createdNode->printStr(libyang::DataFormat::XML, libyang::PrintFlags::Shrink | libyang::PrintFlags::WithSiblings)
- == R"|(<ax xmlns="http://example.com/coze"/>)|"s);
+ == R"|(<ax xmlns="http://example.com/coze">)|"s + origJSON + "</ax>");
}
REQUIRE(!!val);
--
2.43.0
@@ -0,0 +1,57 @@
From f050e7e4a17ef2e221ca000a544042c33c9541fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Thu, 13 Mar 2025 19:21:26 +0100
Subject: [PATCH 14/18] fix DataNode::insertSibling() return value
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
When such an insert happens, the C library returns the node which is now
the first sibling among all of the siblings of the node which was used
as a reference during the insert. Our API was also documented this way,
but we were not doing that.
Reported-by: Irfan <irfan.haslanded@gmail.com>
Bug: https://github.com/CESNET/libyang-cpp/issues/29
Change-Id: Id7f84a31e50212d6e2cbce9ab03a351a3721f767
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
src/DataNode.cpp | 2 +-
tests/data_node.cpp | 7 +++++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/DataNode.cpp b/src/DataNode.cpp
index 84591e5..b899b18 100644
--- a/src/DataNode.cpp
+++ b/src/DataNode.cpp
@@ -711,7 +711,7 @@ DataNode DataNode::insertSibling(DataNode toInsert)
lyd_insert_sibling(this->m_node, toInsert.m_node, &firstSibling);
}, toInsert.parent() ? OperationScope::JustThisNode : OperationScope::AffectsFollowingSiblings, m_refs);
- return DataNode{m_node, m_refs};
+ return DataNode{firstSibling, m_refs};
}
/**
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
index 14470dd..b6ee455 100644
--- a/tests/data_node.cpp
+++ b/tests/data_node.cpp
@@ -973,6 +973,13 @@ TEST_CASE("Data Node manipulation")
REQUIRE(getNumberOrder() == expected);
}
+ DOCTEST_SUBCASE("DataNode::insertSibling")
+ {
+ auto node = ctx.newPath("/example-schema:leafUInt8", "10");
+ REQUIRE(node.insertSibling(ctx.newPath("/example-schema:leafUInt16", "10")).path() == "/example-schema:leafUInt8");
+ REQUIRE(node.insertSibling(ctx.newPath("/example-schema:dummy", "10")).path() == "/example-schema:dummy");
+ }
+
DOCTEST_SUBCASE("DataNode::duplicate")
{
auto root = ctx.parseData(data2, libyang::DataFormat::JSON);
--
2.43.0
@@ -0,0 +1,260 @@
From f958af42bf5d9fbd901ed59ebc1359ac0ddcc00f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Fri, 14 Mar 2025 11:36:50 +0100
Subject: [PATCH 15/18] API/ABI change: opaque node naming
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Our C++ API would ignore the "module name or XML prefix", which turns
out to be *the* relevant part when it comes to opaque node naming. The
prefix is, instead, just that string that might have been inherited from
the parent node when parsing the serialized data; it's an optional
thingy which, if not set explicitly, is implicitly inherited.
Adapt the API for this, and since this *will* break the build, let's
bump the package version.
Change-Id: I199afe5fa7a571034b744531c63b93b9c656563a
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 5 ++---
include/libyang-cpp/Context.hpp | 4 ++--
include/libyang-cpp/DataNode.hpp | 11 ++++++++--
src/Context.cpp | 32 ++++++++++++++++++++--------
src/DataNode.cpp | 19 ++++++++++++++---
tests/data_node.cpp | 36 ++++++++++++++++++++++++++------
6 files changed, 82 insertions(+), 25 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a40fd52..c5fec45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,7 +21,7 @@ add_custom_target(libyang-cpp-version-cmake
cmake/ProjectGitVersionRunner.cmake
)
include(cmake/ProjectGitVersion.cmake)
-set(LIBYANG_CPP_PKG_VERSION "3")
+set(LIBYANG_CPP_PKG_VERSION "4")
prepare_git_version(LIBYANG_CPP_VERSION ${LIBYANG_CPP_PKG_VERSION})
find_package(Doxygen)
@@ -29,8 +29,7 @@ option(WITH_DOCS "Create and install internal documentation (needs Doxygen)" ${D
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
find_package(PkgConfig REQUIRED)
-# FIXME: it's actually 3.7.12, but that hasn't been released yet
-pkg_check_modules(LIBYANG REQUIRED libyang>=3.7.11 IMPORTED_TARGET)
+pkg_check_modules(LIBYANG REQUIRED libyang>=3.10.1 IMPORTED_TARGET)
# FIXME from gcc 14.1 on we should be able to use the calendar/time from libstdc++ and thus remove the date dependency
find_package(date)
diff --git a/include/libyang-cpp/Context.hpp b/include/libyang-cpp/Context.hpp
index baa47b3..ca89063 100644
--- a/include/libyang-cpp/Context.hpp
+++ b/include/libyang-cpp/Context.hpp
@@ -115,8 +115,8 @@ public:
CreatedNodes newPath2(const std::string& path, libyang::JSON json, const std::optional<CreationOptions> options = std::nullopt) const;
CreatedNodes newPath2(const std::string& path, libyang::XML xml, const std::optional<CreationOptions> options = std::nullopt) const;
std::optional<DataNode> newExtPath(const ExtensionInstance& ext, const std::string& path, const std::optional<std::string>& value, const std::optional<CreationOptions> options = std::nullopt) const;
- std::optional<DataNode> newOpaqueJSON(const std::string& moduleName, const std::string& name, const std::optional<libyang::JSON>& value) const;
- std::optional<DataNode> newOpaqueXML(const std::string& moduleName, const std::string& name, const std::optional<libyang::XML>& value) const;
+ std::optional<DataNode> newOpaqueJSON(const OpaqueName& name, const std::optional<libyang::JSON>& value) const;
+ std::optional<DataNode> newOpaqueXML(const OpaqueName& name, const std::optional<libyang::XML>& value) const;
SchemaNode findPath(const std::string& dataPath, const InputOutputNodes inputOutputNodes = InputOutputNodes::Input) const;
Set<SchemaNode> findXPath(const std::string& path) const;
diff --git a/include/libyang-cpp/DataNode.hpp b/include/libyang-cpp/DataNode.hpp
index 851681b..310b5e3 100644
--- a/include/libyang-cpp/DataNode.hpp
+++ b/include/libyang-cpp/DataNode.hpp
@@ -225,15 +225,22 @@ private:
};
/**
- * @brief Contains a (possibly module-qualified) name of an opaque node.
+ * @brief Contains a name of an opaque node.
*
- * This is generic container of a prefix/module string and a name string.
+ * An opaque node always has a name, and a module (or XML namespace) to which this node belongs.
+ * Sometimes, it also has a prefix.
+ *
+ * If the prefix is set *and* the underlying node is an opaque JSON one, then the prefix must be the same as the "module or namespace" name.
+ * If the underlying node is an opaque XML one, then the XML prefix might be something completely different, and in that case the real fun begins.
+ * Review the libayng C manual, this is something that the C++ wrapper doesn't really have under control.
*
* Wraps `ly_opaq_name`.
*/
struct LIBYANG_CPP_EXPORT OpaqueName {
+ std::string moduleOrNamespace;
std::optional<std::string> prefix;
std::string name;
+ std::string pretty() const;
};
/**
diff --git a/src/Context.cpp b/src/Context.cpp
index 287f8c8..fec2f27 100644
--- a/src/Context.cpp
+++ b/src/Context.cpp
@@ -378,17 +378,25 @@ std::optional<DataNode> Context::newExtPath(const ExtensionInstance& ext, const
*
* Wraps `lyd_new_opaq`.
*
- * @param moduleName Node module name, used as a prefix as well
* @param name Name of the created node
* @param value JSON data blob, if any
* @return Returns the newly created node (if created)
*/
-std::optional<DataNode> Context::newOpaqueJSON(const std::string& moduleName, const std::string& name, const std::optional<libyang::JSON>& value) const
+std::optional<DataNode> Context::newOpaqueJSON(const OpaqueName& name, const std::optional<libyang::JSON>& value) const
{
+ if (name.prefix && *name.prefix != name.moduleOrNamespace) {
+ throw Error{"invalid opaque JSON node: prefix \"" + *name.prefix + "\" doesn't match module name \"" + name.moduleOrNamespace + "\""};
+ }
lyd_node* out;
- auto err = lyd_new_opaq(nullptr, m_ctx.get(), name.c_str(), value ? value->content.c_str() : nullptr, nullptr, moduleName.c_str(), &out);
+ auto err = lyd_new_opaq(nullptr,
+ m_ctx.get(),
+ name.name.c_str(),
+ value ? value->content.c_str() : nullptr,
+ name.prefix ? name.prefix->c_str() : nullptr,
+ name.moduleOrNamespace.c_str(),
+ &out);
- throwIfError(err, "Couldn't create an opaque JSON node '"s + moduleName + ':' + name + "'");
+ throwIfError(err, "Couldn't create an opaque JSON node " + name.pretty());
if (out) {
return DataNode{out, std::make_shared<internal_refcount>(m_ctx)};
@@ -403,17 +411,23 @@ std::optional<DataNode> Context::newOpaqueJSON(const std::string& moduleName, co
*
* Wraps `lyd_new_opaq2`.
*
- * @param xmlNamespace Node module namespace
* @param name Name of the created node
* @param value XML data blob, if any
* @return Returns the newly created node (if created)
*/
-std::optional<DataNode> Context::newOpaqueXML(const std::string& xmlNamespace, const std::string& name, const std::optional<libyang::XML>& value) const
+std::optional<DataNode> Context::newOpaqueXML(const OpaqueName& name, const std::optional<libyang::XML>& value) const
{
+ // the XML node naming is "complex", we cannot really check the XML namespace for sanity here
lyd_node* out;
- auto err = lyd_new_opaq2(nullptr, m_ctx.get(), name.c_str(), value ? value->content.c_str() : nullptr, nullptr, xmlNamespace.c_str(), &out);
-
- throwIfError(err, "Couldn't create an opaque XML node '"s + name +"' from namespace '" + xmlNamespace + "'");
+ auto err = lyd_new_opaq2(nullptr,
+ m_ctx.get(),
+ name.name.c_str(),
+ value ? value->content.c_str() : nullptr,
+ name.prefix ? name.prefix->c_str() : nullptr,
+ name.moduleOrNamespace.c_str(),
+ &out);
+
+ throwIfError(err, "Couldn't create an opaque XML node " + name.pretty());
if (out) {
return DataNode{out, std::make_shared<internal_refcount>(m_ctx)};
diff --git a/src/DataNode.cpp b/src/DataNode.cpp
index b899b18..344f1b6 100644
--- a/src/DataNode.cpp
+++ b/src/DataNode.cpp
@@ -1112,9 +1112,9 @@ OpaqueName DataNodeOpaque::name() const
{
auto opaq = reinterpret_cast<lyd_node_opaq*>(m_node);
return OpaqueName{
- .prefix = opaq->name.prefix ? std::optional(opaq->name.prefix) : std::nullopt,
- .name = opaq->name.name
- };
+ .moduleOrNamespace = opaq->name.module_name,
+ .prefix = opaq->name.prefix ? std::optional{opaq->name.prefix} : std::nullopt,
+ .name = opaq->name.name};
}
std::string DataNodeOpaque::value() const
@@ -1122,6 +1122,19 @@ std::string DataNodeOpaque::value() const
return reinterpret_cast<lyd_node_opaq*>(m_node)->value;
}
+std::string OpaqueName::pretty() const
+{
+ if (prefix) {
+ if (*prefix == moduleOrNamespace) {
+ return *prefix + ':' + name;
+ } else {
+ return "{" + moduleOrNamespace + "}, " + *prefix + ':' + name;
+ }
+ } else {
+ return "{" + moduleOrNamespace + "}, " + name;
+ }
+}
+
/**
* Wraps a raw non-null lyd_node pointer.
* @param node The pointer to be wrapped. Must not be null.
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
index b6ee455..a1096a6 100644
--- a/tests/data_node.cpp
+++ b/tests/data_node.cpp
@@ -1969,9 +1969,11 @@ TEST_CASE("Data Node manipulation")
DOCTEST_SUBCASE("opaque nodes for sysrepo ops data discard")
{
- auto discard1 = ctx.newOpaqueJSON("sysrepo", "discard-items", libyang::JSON{"/example-schema:a"});
+ // the "short" form with no prefix
+ auto discard1 = ctx.newOpaqueJSON(libyang::OpaqueName{"sysrepo", std::nullopt, "discard-items"}, libyang::JSON{"/example-schema:a"});
REQUIRE(!!discard1);
- auto discard2 = ctx.newOpaqueJSON("sysrepo", "discard-items", libyang::JSON{"/example-schema:b"});
+ // let's use a prefix form here
+ auto discard2 = ctx.newOpaqueJSON(libyang::OpaqueName{"sysrepo", "sysrepo", "discard-items"}, libyang::JSON{"/example-schema:b"});
REQUIRE(!!discard2);
discard1->insertSibling(*discard2);
REQUIRE(*discard1->printStr(libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings)
@@ -2001,16 +2003,38 @@ TEST_CASE("Data Node manipulation")
auto data = ctx.newPath2("/example-schema:myRpc/outputLeaf", "AHOJ", libyang::CreationOptions::Output).createdNode;
REQUIRE(data);
data->newPath("/example-schema:myRpc/another", "yay", libyang::CreationOptions::Output);
+ std::string prettyName;
- DOCTEST_SUBCASE("JSON") {
- out = ctx.newOpaqueJSON(data->schema().module().name(), "output", std::nullopt);
+ DOCTEST_SUBCASE("JSON no prefix") {
+ out = ctx.newOpaqueJSON({data->schema().module().name(), std::nullopt, "output"}, std::nullopt);
+ prettyName = "{example-schema}, output";
}
- DOCTEST_SUBCASE("XML") {
- out = ctx.newOpaqueXML(data->schema().module().ns(), "output", std::nullopt);
+ DOCTEST_SUBCASE("JSON with prefix") {
+ out = ctx.newOpaqueJSON({data->schema().module().name(), data->schema().module().name(), "output"}, std::nullopt);
+ prettyName = "example-schema:output";
+
+ // wrong prefix is detected
+ REQUIRE_THROWS_WITH_AS(ctx.newOpaqueJSON({data->schema().module().name(), "xxx", "output"}, std::nullopt),
+ R"(invalid opaque JSON node: prefix "xxx" doesn't match module name "example-schema")",
+ libyang::Error);
+ }
+
+ DOCTEST_SUBCASE("XML no prefix") {
+ out = ctx.newOpaqueXML({data->schema().module().ns(), std::nullopt, "output"}, std::nullopt);
+ prettyName = "{http://example.com/coze}, output";
+ }
+
+ DOCTEST_SUBCASE("XML with prefix") {
+ out = ctx.newOpaqueXML({data->schema().module().ns(),
+ data->schema().module().name() /* prefix is a module name, not the XML NS*/,
+ "output"},
+ std::nullopt);
+ prettyName = "{http://example.com/coze}, example-schema:output";
}
REQUIRE(out);
+ REQUIRE(prettyName == out->asOpaque().name().pretty());
data->unlinkWithSiblings();
out->insertChild(*data);
--
2.43.0
@@ -0,0 +1,462 @@
From 8c59ecc5c687f8ee2ce62825835a378b422185f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Fri, 14 Mar 2025 13:41:01 +0100
Subject: [PATCH 16/18] Add a helper for finding opaque nodes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
This is needed for sysrepo where we want to search through the
sysrepo:discard-items top-level opaque nodes.
At first I wanted to simply wrap lyd_find_sibling_opaq_next(), but its
semantics is quite different to what is needed in the code which uses
sysrepo, so here's my attempt at a nice-ish API.
Change-Id: I2571961e42f6d7a121e27c881cacdcfec0e87762
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
include/libyang-cpp/DataNode.hpp | 2 +
src/DataNode.cpp | 49 ++++++
tests/data_node.cpp | 74 +++++++++
tests/yang/sysrepo@2024-10-25.yang | 257 +++++++++++++++++++++++++++++
4 files changed, 382 insertions(+)
create mode 100644 tests/yang/sysrepo@2024-10-25.yang
diff --git a/include/libyang-cpp/DataNode.hpp b/include/libyang-cpp/DataNode.hpp
index 310b5e3..50d6c0e 100644
--- a/include/libyang-cpp/DataNode.hpp
+++ b/include/libyang-cpp/DataNode.hpp
@@ -102,6 +102,7 @@ public:
bool isOpaque() const;
DataNodeOpaque asOpaque() const;
+ std::optional<DataNodeOpaque> firstOpaqueSibling() const;
// TODO: allow setting the `parent` argument
DataNode duplicate(const std::optional<DuplicationOptions> opts = std::nullopt) const;
@@ -241,6 +242,7 @@ struct LIBYANG_CPP_EXPORT OpaqueName {
std::optional<std::string> prefix;
std::string name;
std::string pretty() const;
+ bool matches(const std::string& prefixIsh, const std::string& name) const;
};
/**
diff --git a/src/DataNode.cpp b/src/DataNode.cpp
index 344f1b6..7e87917 100644
--- a/src/DataNode.cpp
+++ b/src/DataNode.cpp
@@ -1135,6 +1135,20 @@ std::string OpaqueName::pretty() const
}
}
+/**
+ * @short Fuzzy-match a real-world name against a combination of "something like a prefix" and "unqualified name"
+ *
+ * Because libyang doesn't propagate inherited prefixes, and because opaque nodes are magic, we seem to require
+ * this "fuzzy matching". It won't properly report a match on opaque nodes with a prefix that's inherited when
+ * using XML namespaces, though.
+ * */
+bool OpaqueName::matches(const std::string& prefixIsh, const std::string& name) const
+{
+ return name == this->name
+ && (prefixIsh == moduleOrNamespace
+ || (!!prefix && prefixIsh == *prefix));
+}
+
/**
* Wraps a raw non-null lyd_node pointer.
* @param node The pointer to be wrapped. Must not be null.
@@ -1305,4 +1319,39 @@ bool DataNode::siblingsEqual(const libyang::DataNode& other, const DataCompare f
}
}
+/**
+ * @short Find the first opaque node among the siblings
+ *
+ * This function was inspired by `lyd_find_sibling_opaq_next()`.
+ * */
+std::optional<DataNodeOpaque> DataNode::firstOpaqueSibling() const
+{
+ struct lyd_node *candidate = m_node;
+
+ // Skip all non-opaque nodes; libyang guarantees to have them first, followed by a (possibly empty) set
+ // of opaque nodes. This is not documented anywhere, but it was explicitly confirmed by the maintainer:
+ //
+ // JK: can I rely on all non-opaque nodes being listed first among the siblings, and then all opaque nodes
+ // in one continuous sequence (but with an unspecified order among the opaque nodes themselves)?
+ //
+ // MV: yep
+ while (candidate && candidate->schema) {
+ candidate = candidate->next;
+ }
+
+ // walk back through the opaque nodes; however, libyang lists are not your regular linked lists
+ while (candidate
+ && !candidate->prev->schema // don't go from the first opaque node through the non-opaque ones
+ && candidate->prev->next // don't wrap from the first node to the last one in case all of them are opaque
+ ) {
+ candidate = candidate->prev;
+ }
+
+ if (candidate) {
+ return DataNode{candidate, m_refs}.asOpaque();
+ }
+
+ return std::nullopt;
+}
+
}
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
index a1096a6..db5a28e 100644
--- a/tests/data_node.cpp
+++ b/tests/data_node.cpp
@@ -1982,6 +1982,80 @@ TEST_CASE("Data Node manipulation")
"sysrepo:discard-items": "/example-schema:b"
}
)");
+
+ // check that a list which only consists of opaque nodes doesn't break our iteration
+ REQUIRE(!!discard1->firstOpaqueSibling());
+ REQUIRE(*discard1->firstOpaqueSibling() == *discard1);
+ REQUIRE(!!discard2->firstOpaqueSibling());
+ REQUIRE(*discard2->firstOpaqueSibling() == *discard1);
+
+ auto leafInt16 = ctx.newPath("/example-schema:leafInt16", "666");
+ leafInt16.insertSibling(*discard1);
+ REQUIRE(*discard1->firstSibling().printStr(libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings)
+ == R"({
+ "example-schema:leafInt16": 666,
+ "sysrepo:discard-items": "/example-schema:a",
+ "sysrepo:discard-items": "/example-schema:b"
+}
+)");
+ REQUIRE(leafInt16.firstSibling().path() == "/example-schema:leafInt16");
+ REQUIRE(discard1->firstSibling().path() == "/example-schema:leafInt16");
+ REQUIRE(discard2->firstSibling().path() == "/example-schema:leafInt16");
+
+ auto dummy = ctx.newPath("/example-schema:dummy", "blah");
+ auto opaqueLeaf = ctx.newPath("/example-schema:leafInt32", std::nullopt, libyang::CreationOptions::Opaque);
+ opaqueLeaf.newAttrOpaqueJSON("ietf-netconf", "operation", "delete");
+ dummy.insertSibling(opaqueLeaf);
+
+ // FIXME reword this: this one might not be handled by sysrepo, but we want it for our fuzzy matcher testing anyway
+ auto discard3 = ctx.newOpaqueXML(libyang::OpaqueName{"http://www.sysrepo.org/yang/sysrepo", "sysrepo", "discard-items"}, libyang::XML{"/example-schema:c"});
+ REQUIRE(!!discard3);
+ // notice that it's printed without a proper prefix at first...
+ REQUIRE(*discard3->printStr(libyang::DataFormat::JSON, libyang::PrintFlags::Shrink)
+ == R"({"discard-items":"/example-schema:c"})");
+ // ...but after loading the module, the proper module is added back
+ ctx.parseModule(TESTS_DIR / "yang" / "sysrepo@2024-10-25.yang", libyang::SchemaFormat::YANG);
+ REQUIRE(*discard3->printStr(libyang::DataFormat::JSON, libyang::PrintFlags::Shrink)
+ == R"({"sysrepo:discard-items":"/example-schema:c"})");
+
+ dummy.insertSibling(*discard3);
+ leafInt16.insertSibling(dummy);
+ REQUIRE(*discard1->firstSibling().printStr(libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings)
+ == R"({
+ "example-schema:dummy": "blah",
+ "example-schema:leafInt16": 666,
+ "sysrepo:discard-items": "/example-schema:a",
+ "sysrepo:discard-items": "/example-schema:b",
+ "example-schema:leafInt32": "",
+ "@example-schema:leafInt32": {
+ "ietf-netconf:operation": "delete"
+ },
+ "sysrepo:discard-items": "/example-schema:c"
+}
+)");
+
+ REQUIRE(dummy.firstOpaqueSibling() == discard1);
+ REQUIRE(dummy.firstOpaqueSibling() != discard2);
+ REQUIRE(leafInt16.firstOpaqueSibling() == discard1);
+ REQUIRE(opaqueLeaf.firstOpaqueSibling() == discard1);
+ REQUIRE(discard1->firstOpaqueSibling() == discard1);
+ REQUIRE(discard2->firstOpaqueSibling() == discard1);
+ REQUIRE(discard3->firstOpaqueSibling() == discard1);
+ REQUIRE(discard1->asOpaque().name().matches("sysrepo", "discard-items"));
+ REQUIRE(!discard1->asOpaque().name().matches("http://www.sysrepo.org/yang/sysrepo", "discard-items"));
+ REQUIRE(discard2->asOpaque().name().matches("sysrepo", "discard-items"));
+ REQUIRE(!discard2->asOpaque().name().matches("http://www.sysrepo.org/yang/sysrepo", "discard-items"));
+ REQUIRE(discard3->asOpaque().name().matches("sysrepo", "discard-items"));
+ REQUIRE(discard3->asOpaque().name().matches("http://www.sysrepo.org/yang/sysrepo", "discard-items"));
+ REQUIRE(!opaqueLeaf.asOpaque().name().matches("sysrepo", "discard-items"));
+
+ REQUIRE(!!dummy.firstOpaqueSibling()->nextSibling());
+ REQUIRE(dummy.firstOpaqueSibling()->nextSibling() == discard2);
+ REQUIRE(!!dummy.firstOpaqueSibling()->nextSibling()->nextSibling());
+ REQUIRE(dummy.firstOpaqueSibling()->nextSibling()->nextSibling() == opaqueLeaf);
+ REQUIRE(!!dummy.firstOpaqueSibling()->nextSibling()->nextSibling()->nextSibling());
+ REQUIRE(dummy.firstOpaqueSibling()->nextSibling()->nextSibling()->nextSibling() == discard3);
+ REQUIRE(!dummy.firstOpaqueSibling()->nextSibling()->nextSibling()->nextSibling()->nextSibling());
}
DOCTEST_SUBCASE("RESTCONF RPC output")
diff --git a/tests/yang/sysrepo@2024-10-25.yang b/tests/yang/sysrepo@2024-10-25.yang
new file mode 100644
index 0000000..f5bc32c
--- /dev/null
+++ b/tests/yang/sysrepo@2024-10-25.yang
@@ -0,0 +1,257 @@
+module sysrepo {
+ namespace "http://www.sysrepo.org/yang/sysrepo";
+ prefix sr;
+
+ yang-version 1.1;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ import ietf-datastores {
+ prefix ds;
+ }
+
+ import ietf-yang-metadata {
+ prefix md;
+ revision-date 2016-08-05;
+ }
+
+ organization
+ "CESNET";
+
+ contact
+ "Author: Michal Vasko
+ <mvasko@cesnet.cz>";
+
+ description
+ "Sysrepo YANG datastore internal attributes and information.";
+
+ revision "2024-10-25" {
+ description
+ "Removed redundant metadata used for push operational data.";
+ }
+
+ revision "2019-07-10" {
+ description
+ "Initial revision.";
+ }
+
+ typedef module-ref {
+ description
+ "Reference to a module.";
+ type leafref {
+ path "/sysrepo-modules/module/name";
+ }
+ }
+
+ md:annotation operation {
+ type enumeration {
+ enum none {
+ description
+ "Node with this operation must exist but does not affect the datastore in any way.";
+ reference
+ "RFC 6241 section 7.2.: default-operation";
+ }
+ enum ether {
+ description
+ "Node with this operation does not have to exist and does not affect the datastore in any way.";
+ }
+ enum purge {
+ description
+ "Node with this operation represents an arbitrary generic node instance and all
+ the instances will be deleted.";
+ }
+ }
+ description
+ "Additional proprietary <edit-config> operations used internally.";
+ reference
+ "RFC 6241 section 7.2.";
+ }
+
+ identity notification {
+ base ds:datastore;
+ description
+ "Special datastore for storing notifications for replay.";
+ }
+
+ grouping module-info-grp {
+ leaf name {
+ type string;
+ description
+ "Module name.";
+ }
+
+ leaf revision {
+ type string;
+ description
+ "Module revision.";
+ }
+
+ leaf-list enabled-feature {
+ type string;
+ description
+ "List of all the enabled features.";
+ }
+
+ list plugin {
+ key "datastore";
+ description
+ "Module datastore plugin handling specific datastore data.";
+
+ leaf datastore {
+ type identityref {
+ base ds:datastore;
+ }
+ description
+ "Datastore of this plugin.";
+ }
+
+ leaf name {
+ type string;
+ mandatory true;
+ description
+ "Specific plugin name as present in the plugin structures.";
+ }
+ }
+ }
+
+ grouping deps-grp {
+ list lref {
+ description
+ "Dependency of a leafref node.";
+
+ leaf target-path {
+ type yang:xpath1.0;
+ mandatory true;
+ description
+ "Path identifying the leafref target node.";
+ }
+
+ leaf target-module {
+ type module-ref;
+ mandatory true;
+ description
+ "Foreign target module of the leafref.";
+ }
+ }
+
+ list inst-id {
+ description
+ "Dependency of an instance-identifier node.";
+
+ leaf source-path {
+ type yang:xpath1.0;
+ mandatory true;
+ description
+ "Path identifying the instance-identifier node.";
+ }
+
+ leaf default-target-path {
+ type yang:xpath1.0;
+ description
+ "Default instance-identifier value.";
+ }
+ }
+
+ list xpath {
+ description
+ "Dependency of an XPath expression - must or when statement.";
+
+ leaf expression {
+ type yang:xpath1.0;
+ mandatory true;
+ description
+ "XPath expression of the dependency - must or when statement argument.";
+ }
+
+ leaf-list target-module {
+ type module-ref;
+ description
+ "Foreign modules with the data needed for evaluation of the XPath.";
+ }
+ }
+ }
+
+ container sysrepo-modules {
+ config false;
+ description
+ "All installed Sysrepo modules.";
+
+ leaf content-id {
+ type uint32;
+ mandatory true;
+ description
+ "Sysrepo module-set content-id to be used for its generated yang-library data.";
+ }
+
+ list module {
+ key "name";
+ description
+ "Sysrepo module.";
+
+ uses module-info-grp;
+
+ leaf replay-support {
+ type yang:date-and-time;
+ description
+ "Present only if the module supports replay. Means the earliest stored notification if any present.
+ Otherwise the time the replay support was switched on.";
+ }
+
+ container deps {
+ description
+ "Module data dependencies on other modules.";
+ uses deps-grp;
+ }
+
+ leaf-list inverse-deps {
+ type module-ref;
+ description
+ "List of modules that depend on this module.";
+ }
+
+ list rpc {
+ key "path";
+ description
+ "Module RPC/actions.";
+
+ leaf path {
+ type yang:xpath1.0;
+ description
+ "Path identifying the operation.";
+ }
+
+ container in {
+ description
+ "Operation input dependencies.";
+ uses deps-grp;
+ }
+
+ container out {
+ description
+ "Operation output dependencies.";
+ uses deps-grp;
+ }
+ }
+
+ list notification {
+ key "path";
+ description
+ "Module notifications.";
+
+ leaf path {
+ type yang:xpath1.0;
+ description
+ "Path identifying the notification.";
+ }
+
+ container deps {
+ description
+ "Notification dependencies.";
+ uses deps-grp;
+ }
+ }
+ }
+ }
+}
--
2.43.0
@@ -0,0 +1,56 @@
From dab8c9aac96063ccb8541d5d1795ee89b75faeee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Wed, 2 Apr 2025 11:50:24 -0700
Subject: [PATCH 17/18] build: link to libpcre2 explicitly
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
This is apparently a problem on Mac OS X builds where the transitive
dependency via libyang doesn't take effect:
Undefined symbols for architecture arm64:
"_pcre2_code_free_8", referenced from:
libyang::Regex::~Regex() in Regex.cpp.o
libyang::Regex::~Regex() in Regex.cpp.o
ld: symbol(s) not found for architecture arm64
Let's fix this by linking with libpcre2-8 directly.
We're using a different approach than libyang; they have their own CMake
wrapper. I find it easier to work with pkg-config modules, so let's try
it that way.
Change-Id: I1a64407d852161595b7dca654433190002cc3600
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5fec45..4e009aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,9 @@ pkg_check_modules(LIBYANG REQUIRED libyang>=3.10.1 IMPORTED_TARGET)
# FIXME from gcc 14.1 on we should be able to use the calendar/time from libstdc++ and thus remove the date dependency
find_package(date)
+# libyang::Regex::~Regex() bypasses libyang and calls out to libpcre directly
+pkg_check_modules(LIBPCRE2 REQUIRED libpcre2-8 IMPORTED_TARGET)
+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include(CheckIncludeFileCXX)
@@ -64,7 +67,7 @@ add_library(yang-cpp
src/utils/newPath.cpp
)
-target_link_libraries(yang-cpp PRIVATE PkgConfig::LIBYANG)
+target_link_libraries(yang-cpp PRIVATE PkgConfig::LIBYANG PkgConfig::LIBPCRE2)
# We do not offer any long-term API/ABI guarantees. To make stuff easier for downstream consumers,
# we will be bumping both API and ABI versions very deliberately.
# There will be no attempts at semver tracking, for example.
--
2.43.0
@@ -0,0 +1,66 @@
From 7519fcd35216072a6b1eebe2a79e19789be345a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Wed, 9 Apr 2025 15:35:37 +0200
Subject: [PATCH 18/18] CI: renamed project upstream
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: I5447f243297fbfde7c364eb3919b00db239bd069
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
.zuul.yaml | 4 ++--
README.md | 2 +-
ci/build.sh | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.zuul.yaml b/.zuul.yaml
index b41c490..7b92766 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -5,13 +5,13 @@
required-projects:
- name: github/CESNET/libyang
override-checkout: devel
- - name: github/onqtam/doctest
+ - name: github/doctest/doctest
override-checkout: v2.3.6
- f38-clang-asan-ubsan:
required-projects: &projects
- name: github/CESNET/libyang
override-checkout: devel
- - name: github/onqtam/doctest
+ - name: github/doctest/doctest
override-checkout: v2.4.11
- f38-clang-tsan:
required-projects: *projects
diff --git a/README.md b/README.md
index d76975b..8291e00 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Object lifetimes are managed automatically via RAII.
- [libyang v3](https://github.com/CESNET/libyang) - the `devel` branch (even for the `master` branch of *libyang-cpp*)
- C++20 compiler (e.g., GCC 10.x+, clang 10+)
- CMake 3.19+
-- optionally for built-in tests, [Doctest](https://github.com/onqtam/doctest/) as a C++ unit test framework
+- optionally for built-in tests, [Doctest](https://github.com/doctest/doctest/) as a C++ unit test framework
- optionally for the docs, Doxygen
## Building
diff --git a/ci/build.sh b/ci/build.sh
index d06b646..0867f07 100755
--- a/ci/build.sh
+++ b/ci/build.sh
@@ -73,7 +73,7 @@ build_n_test() {
}
build_n_test github/CESNET/libyang -DENABLE_BUILD_TESTS=ON -DENABLE_VALGRIND_TESTS=OFF
-build_n_test github/onqtam/doctest -DDOCTEST_WITH_TESTS=OFF
+build_n_test github/doctest/doctest -DDOCTEST_WITH_TESTS=OFF
build_n_test ${ZUUL_PROJECT_NAME} -DBUILD_TESTING=ON
pushd ${BUILD_DIR}/${ZUUL_PROJECT_NAME}
--
2.43.0
+27
View File
@@ -0,0 +1,27 @@
diff -urN lowdown-VERSION_1_0_2.orig/configure lowdown-VERSION_1_0_2/configure
--- lowdown-VERSION_1_0_2.orig/configure 2025-03-21 12:58:06.151106271 +0000
+++ lowdown-VERSION_1_0_2/configure 2025-03-21 13:20:20.649825864 +0000
@@ -61,12 +61,7 @@
MAKE_FLAGS=""
-if [ -n "${MAKELEVEL}" ]; then
- if [ "${MAKELEVEL}" -gt 0 ] ; then
- MAKE_FLAGS="--no-print-directory"
- echo "all:" | make ${MAKE_FLAGS} -sf - 2>/dev/null || MAKE_FLAGS=""
- fi
-fi
+MAKE_FLAGS="--no-print-directory"
if [ -n "$MAKE_FLAGS" ]; then
echo "GNU submake detected: using --no-print-directory" 1>&2
@@ -79,9 +74,6 @@
# in.
#----------------------------------------------------------------------
-AR=`printf "all:\\n\\t@echo \\\$(AR)\\n" | make ${MAKE_FLAGS} -sf -`
-CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | make ${MAKE_FLAGS} -sf -`
-CFLAGS=`printf "all:\\n\\t@echo \\\$(CFLAGS)\\n" | make ${MAKE_FLAGS} -sf -`
CFLAGS="${CFLAGS} -g -W -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes"
CFLAGS="${CFLAGS} -Wwrite-strings -Wno-unused-parameter"
LDLIBS=
+1 -1
View File
@@ -9,7 +9,7 @@ NGHTTP2_ASIO_SITE = https://github.com/kernelkit/nghttp2-asio.git
NGHTTP2_ASIO_SITE_METHOD = git
NGHTTP2_ASIO_LICENSE = MIT
NGHTTP2_ASIO_LICENSE_FILES = COPYING
NGHTTP2_ASIO_DEPENDENCIES = boost nghttp2
NGHTTP2_ASIO_DEPENDENCIES = boost nghttp2 openssl
NGHTTP2_ASIO_INSTALL_STAGING = YES
NGHTTP2_ASIO_AUTOGEN = YES
NGHTTP2_ASIO_AUTORECONF = YES
+2 -2
View File
@@ -10,8 +10,8 @@ PYTHON_LIBYANG_SITE = https://files.pythonhosted.org/packages/91/2e/ff13ee16c874
PYTHON_LIBYANG_SETUP_TYPE = setuptools
PYTHON_LIBYANG_LICENSE = MIT
PYTHON_LIBYANG_LICENSE_FILES = LICENSE
PYTHON_LIBYANG_DEPENDENCIES = python-cython python-cffi
HOST_PYTHON_LIBYANG_DEPENDENCIES = host-python-cython host-python-cffi
PYTHON_LIBYANG_DEPENDENCIES = python-cython python-cffi libyang
HOST_PYTHON_LIBYANG_DEPENDENCIES = host-python-cython host-python-cffi host-libyang
$(eval $(python-package))
$(eval $(host-python-package))
@@ -1,12 +1,12 @@
From 9622a68eba4aeaa60619b4c33d050ce91b27653d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Tue, 8 Oct 2024 12:22:49 +0200
Subject: [PATCH 01/20] restconf: report the list key values when they differ
Subject: [PATCH 01/44] restconf: report the list key values when they differ
between URI and data
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
For creating (leaf-)list instances with PUT and PATCH methods one has
to specify the list key values in the URI and in the data as well.
@@ -1,11 +1,11 @@
From 070cffb48fda789910581930265d4624a7213e1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 16 Oct 2024 11:02:45 +0200
Subject: [PATCH 02/20] uri: rename url-encoding to percent-encoding
Subject: [PATCH 02/44] uri: rename url-encoding to percent-encoding
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
RFC 3986 [1] calls it the percent-encoding, let's be consistent.
@@ -1,11 +1,11 @@
From 8a233202647f24538f2bbb8fff1e38d52e3599a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 16 Oct 2024 11:05:09 +0200
Subject: [PATCH 03/20] uri: correct x3 rule class names
Subject: [PATCH 03/44] uri: correct x3 rule class names
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Fixes: e06d5bf ("server: parser for data resources in URI paths")
Change-Id: Ic953e568d841032113ede1c0e896574361c0ebe2
@@ -1,12 +1,12 @@
From 96cbf730010ee9539d05d0d72697dc960b3a938c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 7 Oct 2024 20:46:24 +0200
Subject: [PATCH 04/20] restconf: parser should work on raw percent-encoded
Subject: [PATCH 04/44] restconf: parser should work on raw percent-encoded
paths
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
The difference between nghttp2's uri_ref::path and raw_path is that the
raw_path keeps the percent encoding, while the path converts the percent
@@ -1,12 +1,12 @@
From 8b13c1e4ccaa61a241674c27063439e257fa88de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 2 Oct 2024 20:21:28 +0200
Subject: [PATCH 05/20] restconf: list key values checking must respect
Subject: [PATCH 05/44] restconf: list key values checking must respect
libyang's canonicalization
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
While dealing with the issue that was fixed in the previous commit we
realized that the issue is deeper. Not only that our parser rejected
@@ -1,11 +1,11 @@
From fda47b6a6cfdaecc24e96c4d6138c6de3ef116e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 7 Oct 2024 21:21:22 +0200
Subject: [PATCH 06/20] tests: test querying lists with union keys
Subject: [PATCH 06/44] tests: test querying lists with union keys
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Test that we correctly work with keys that are unions of something
that can have a module namespace and that must not have it.
@@ -1,11 +1,11 @@
From 27ef5bc87fdeb70a77609da6ec18ee5c28656bb6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Tue, 29 Oct 2024 18:54:55 +0100
Subject: [PATCH 07/20] error handling in sysrepo has changed
Subject: [PATCH 07/44] error handling in sysrepo has changed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/7969
Change-Id: Id028806ed49114cba4c55e2874bcf3fc98308bdc
@@ -1,11 +1,11 @@
From 6819561d97e38569c319e36ca2e99768036b4032 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 21 Aug 2024 19:18:08 +0200
Subject: [PATCH 08/20] restconf: support fields query parameter
Subject: [PATCH 08/44] restconf: support fields query parameter
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
This patch adds support for fields query parameter [1].
@@ -1,11 +1,11 @@
From 48d9b6ba3f3f892b9060b76b505d2f9a3aeb9e02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 25 Nov 2024 09:15:55 +0100
Subject: [PATCH 09/20] cmake: adhere to CMP0167
Subject: [PATCH 09/44] cmake: adhere to CMP0167
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
After locally updating to cmake 3.30 I have seen a warning that our way
of finding boost library is deprecated [1].
@@ -1,11 +1,11 @@
From 64997543d48236cd2aae417568bc54d32c54df21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Mon, 2 Dec 2024 14:43:36 +0100
Subject: [PATCH 10/20] Fix compatibility with pam_wrapper 1.1.6+
Subject: [PATCH 10/44] Fix compatibility with pam_wrapper 1.1.6+
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
An year ago I reported a bug that the pam_wrapper project says that they
use a variable called `PAM_WRAPPER_DISABLE_DEEPBIND`, but in fact they
@@ -1,11 +1,11 @@
From 849aa35274d5e07726cb849fe724962754b3fa29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 20:20:48 +0100
Subject: [PATCH 11/20] tests: add missing pragma once
Subject: [PATCH 11/44] tests: add missing pragma once
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Change-Id: I269c20e5a914aa8c7bc9431147dd9785ea1aedda
Signed-off-by: Mattias Walström <lazzer@gmail.com>
@@ -1,12 +1,12 @@
From 60eac2b2d60f8f1918a0914272975dd53f527c01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 19:36:10 +0100
Subject: [PATCH 12/20] tests: extend clientRequest wrappers interface and use
Subject: [PATCH 12/44] tests: extend clientRequest wrappers interface and use
it
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
This is a preparation for refactoring in the next few commits.
I will generalize the clientRequest interface to accept server
@@ -1,11 +1,11 @@
From 0beaee041fd4fcfbebcbb2912eb6b26ec71f50c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 20:01:54 +0100
Subject: [PATCH 13/20] tests: move stuff from the header file into cpp file
Subject: [PATCH 13/44] tests: move stuff from the header file into cpp file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Allright, I have had enough. I am no longer waiting for a minute for a
recompilation of one test.
@@ -1,11 +1,11 @@
From 53aa2e23ee8acc1881487f3969c2c58fb29437be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 20:08:53 +0100
Subject: [PATCH 14/20] tests: rename datastoreUtils to event_watchers
Subject: [PATCH 14/44] tests: rename datastoreUtils to event_watchers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
The next commit will move RESTCONF notification watchers there, I think
the new name is more appropriate.
@@ -1,11 +1,11 @@
From f86df829979a26d5192a86c3b43c1393dcba7140 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Tue, 3 Dec 2024 11:45:41 +0100
Subject: [PATCH 15/20] tests: rename NotificationWatcher
Subject: [PATCH 15/44] tests: rename NotificationWatcher
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
This watches notifications going through RESTCONF, so I think
RestconfNotificatonWatcher is better name for this.
@@ -1,11 +1,11 @@
From 30d704588fa7eb9d32f66296ec5f6784f082869e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 20:11:32 +0100
Subject: [PATCH 16/20] tests: make NotificationWatcher reusable
Subject: [PATCH 16/44] tests: make NotificationWatcher reusable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
We will need some parts of this in yang push tests
@@ -1,11 +1,11 @@
From 36943051d8563bee0c9cf89eec28acf5d3617272 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Tue, 3 Dec 2024 12:02:24 +0100
Subject: [PATCH 17/20] tests: helper function to construct server URI
Subject: [PATCH 17/44] tests: helper function to construct server URI
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
Change-Id: Ic7c03b32a29b07464291f99027530010a7902f77
Signed-off-by: Mattias Walström <lazzer@gmail.com>
@@ -1,11 +1,11 @@
From 7d15f59d20079ba94224e0bc308682aa5a004483 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 2 Dec 2024 20:15:05 +0100
Subject: [PATCH 18/20] tests: make SSEClient reusable
Subject: [PATCH 18/44] tests: make SSEClient reusable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
We will need it in yang push tests
@@ -1,11 +1,11 @@
From 3e3e492f4801df56226a5aff5d82bfa86c9d3812 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Tue, 3 Dec 2024 13:59:52 +0100
Subject: [PATCH 19/20] tests: fix deadlock in tests
Subject: [PATCH 19/44] tests: fix deadlock in tests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
In the case the client never requests (because of misconfiguration or
something else) the test would still be waiting for somebody to
@@ -1,11 +1,11 @@
From ed0ff23f7ad341d663484f0b2a617cd3bc4923c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Tue, 3 Dec 2024 19:27:49 +0100
Subject: [PATCH 20/20] restconf: make as_restconf_notification reusable
Subject: [PATCH 20/44] restconf: make as_restconf_notification reusable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Addiva Elektronik
Organization: Wires
The YANG-PUSH notifications are supposed to be wrapped in this too, so
this needs to be accessible from multiple places.
@@ -1,17 +1,25 @@
From f7307481fc4ca167592acf925136e5f8a51e2150 Mon Sep 17 00:00:00 2001
From: Jan Kundrát <jan.kundrat@cesnet.cz>
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Wed, 18 Dec 2024 17:26:15 +0100
Subject: [PATCH] Update dependencies
Subject: [PATCH 21/44] Update dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/8134
Change-Id: Ib170aa61600ffb9089460247f762ff5a947dd6c6
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 2 +-
tests/restconf-writing.cpp | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 22bce32..5ae8062 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,7 +74,7 @@
@@ -74,7 +74,7 @@ find_package(PkgConfig)
pkg_check_modules(nghttp2 REQUIRED IMPORTED_TARGET libnghttp2_asio>=0.0.90 libnghttp2)
find_package(Boost REQUIRED CONFIG COMPONENTS system thread)
@@ -24,7 +32,7 @@ diff --git a/tests/restconf-writing.cpp b/tests/restconf-writing.cpp
index 0932984..d37ab03 100644
--- a/tests/restconf-writing.cpp
+++ b/tests/restconf-writing.cpp
@@ -772,7 +772,7 @@
@@ -772,7 +772,7 @@ TEST_CASE("writing data")
{
"error-type": "protocol",
"error-tag": "invalid-value",
@@ -33,7 +41,7 @@ index 0932984..d37ab03 100644
}
]
}
@@ -855,7 +855,7 @@
@@ -855,7 +855,7 @@ TEST_CASE("writing data")
{
"error-type": "protocol",
"error-tag": "invalid-value",
@@ -42,7 +50,7 @@ index 0932984..d37ab03 100644
}
]
}
@@ -1560,7 +1560,7 @@
@@ -1560,7 +1560,7 @@ TEST_CASE("writing data")
{
"error-type": "protocol",
"error-tag": "invalid-value",
@@ -51,7 +59,7 @@ index 0932984..d37ab03 100644
}
]
}
@@ -1626,7 +1626,7 @@
@@ -1626,7 +1626,7 @@ TEST_CASE("writing data")
{
"error-type": "protocol",
"error-tag": "invalid-value",
@@ -60,3 +68,6 @@ index 0932984..d37ab03 100644
}
]
}
--
2.43.0
@@ -0,0 +1,104 @@
From c967e688c53000519ceb6030e8282296e4846d3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 13 Jan 2025 18:29:29 +0100
Subject: [PATCH 22/44] restconf: add RAII datastore switch
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Copied from sysrepo-ietf-alarms[1].
[1] https://github.com/CESNET/sysrepo-ietf-alarms/blob/4870dbee30a5ec56135d4f4cb5818f191c089c34/src/utils/sysrepo.cpp
Change-Id: I51738d06187e141ebd662e7b9421ca995380cafc
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 1 +
src/restconf/utils/sysrepo.cpp | 25 +++++++++++++++++++++++++
src/restconf/utils/sysrepo.h | 29 +++++++++++++++++++++++++++++
3 files changed, 55 insertions(+)
create mode 100644 src/restconf/utils/sysrepo.cpp
create mode 100644 src/restconf/utils/sysrepo.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5ae8062..7f3a9c0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -114,6 +114,7 @@ add_library(rousette-restconf STATIC
src/restconf/YangSchemaLocations.cpp
src/restconf/uri.cpp
src/restconf/utils/dataformat.cpp
+ src/restconf/utils/sysrepo.cpp
src/restconf/utils/yang.cpp
)
target_link_libraries(rousette-restconf PUBLIC rousette-http rousette-sysrepo rousette-auth Boost::system Threads::Threads PRIVATE date::date-tz)
diff --git a/src/restconf/utils/sysrepo.cpp b/src/restconf/utils/sysrepo.cpp
new file mode 100644
index 0000000..622ab27
--- /dev/null
+++ b/src/restconf/utils/sysrepo.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020, 2022 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
+ */
+
+#include <sysrepo-cpp/Connection.hpp>
+#include "sysrepo.h"
+
+namespace rousette::restconf {
+
+ScopedDatastoreSwitch::ScopedDatastoreSwitch(sysrepo::Session session, sysrepo::Datastore ds)
+ : m_session(std::move(session))
+ , m_oldDatastore(m_session.activeDatastore())
+{
+ m_session.switchDatastore(ds);
+}
+
+ScopedDatastoreSwitch::~ScopedDatastoreSwitch()
+{
+ m_session.switchDatastore(m_oldDatastore);
+}
+
+}
diff --git a/src/restconf/utils/sysrepo.h b/src/restconf/utils/sysrepo.h
new file mode 100644
index 0000000..da6c359
--- /dev/null
+++ b/src/restconf/utils/sysrepo.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020, 2022 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
+ */
+
+#pragma once
+
+#include <libyang-cpp/Context.hpp>
+#include <sysrepo-cpp/Session.hpp>
+
+namespace rousette::restconf {
+
+/** @brief Ensures that session switches to provided datastore and when the object gets destroyed the session switches back to the original datastore. */
+class ScopedDatastoreSwitch {
+ sysrepo::Session m_session;
+ sysrepo::Datastore m_oldDatastore;
+
+public:
+ ScopedDatastoreSwitch(sysrepo::Session session, sysrepo::Datastore ds);
+ ~ScopedDatastoreSwitch();
+ ScopedDatastoreSwitch(const ScopedDatastoreSwitch&) = delete;
+ ScopedDatastoreSwitch(ScopedDatastoreSwitch&&) = delete;
+ ScopedDatastoreSwitch& operator=(const ScopedDatastoreSwitch&) = delete;
+ ScopedDatastoreSwitch& operator=(ScopedDatastoreSwitch&&) = delete;
+};
+
+}
--
2.43.0
@@ -0,0 +1,30 @@
From 05274bd27b886e67accc86be7153ed76465b156e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 15 Jan 2025 17:56:26 +0100
Subject: [PATCH 23/44] restconf: add missing pragma once
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Change-Id: I6d337c99351e24226fb322a40ba2e96655104860
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
src/restconf/NotificationStream.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/restconf/NotificationStream.h b/src/restconf/NotificationStream.h
index 6840f11..3029a0d 100644
--- a/src/restconf/NotificationStream.h
+++ b/src/restconf/NotificationStream.h
@@ -5,6 +5,7 @@
*
*/
+#pragma once
#include <optional>
#include <sysrepo-cpp/Session.hpp>
#include <sysrepo-cpp/Subscription.hpp>
--
2.43.0
@@ -0,0 +1,108 @@
From bd7def1768e360cc491d56805f7c16784c2f4fbe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Wed, 15 Jan 2025 18:27:25 +0100
Subject: [PATCH 24/44] restconf: make fetching replay info reusable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
We are querying sysrepo for replay support in our modules for NETCONF
stream. This part of code will be reused for dynamic subscriptions to
NETCONF stream as well, so let's make it reusable.
Change-Id: Id5bc656619acb8e56dfafde23b03107139d34e94
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
src/restconf/NotificationStream.cpp | 57 +++++++++++++++++------------
1 file changed, 34 insertions(+), 23 deletions(-)
diff --git a/src/restconf/NotificationStream.cpp b/src/restconf/NotificationStream.cpp
index eeddc04..e00c39d 100644
--- a/src/restconf/NotificationStream.cpp
+++ b/src/restconf/NotificationStream.cpp
@@ -50,6 +50,36 @@ bool canBeSubscribed(const libyang::Module& mod)
{
return mod.implemented() && mod.name() != "sysrepo";
}
+
+struct SysrepoReplayInfo {
+ bool enabled;
+ std::optional<sysrepo::NotificationTimeStamp> earliestNotification;
+};
+
+SysrepoReplayInfo sysrepoReplayInfo(sysrepo::Session& session)
+{
+ decltype(sysrepo::ModuleReplaySupport::earliestNotification) globalEarliestNotification;
+ bool replayEnabled = false;
+
+ for (const auto& mod : session.getContext().modules()) {
+ if (!canBeSubscribed(mod)) {
+ continue;
+ }
+
+ auto replay = session.getConnection().getModuleReplaySupport(mod.name());
+ replayEnabled |= replay.enabled;
+
+ if (replay.earliestNotification) {
+ if (!globalEarliestNotification) {
+ globalEarliestNotification = replay.earliestNotification;
+ } else {
+ globalEarliestNotification = std::min(*replay.earliestNotification, *globalEarliestNotification);
+ }
+ }
+ }
+
+ return {replayEnabled, globalEarliestNotification};
+}
}
namespace rousette::restconf {
@@ -114,28 +144,9 @@ void NotificationStream::activate()
/** @brief Creates and fills ietf-restconf-monitoring:restconf-state/stream. To be called in oper callback. */
void notificationStreamList(sysrepo::Session& session, std::optional<libyang::DataNode>& parent, const std::string& streamsPrefix)
{
+ const auto replayInfo = sysrepoReplayInfo(session);
static const auto prefix = "/ietf-restconf-monitoring:restconf-state/streams/stream[name='NETCONF']"s;
- decltype(sysrepo::ModuleReplaySupport::earliestNotification) globalEarliestNotification;
- bool replayEnabled = false;
-
- for (const auto& mod : session.getContext().modules()) {
- if (!canBeSubscribed(mod)) {
- continue;
- }
-
- auto replay = session.getConnection().getModuleReplaySupport(mod.name());
- replayEnabled |= replay.enabled;
-
- if (replay.earliestNotification) {
- if (!globalEarliestNotification) {
- globalEarliestNotification = replay.earliestNotification;
- } else {
- globalEarliestNotification = std::min(*replay.earliestNotification, *globalEarliestNotification);
- }
- }
- }
-
if (!parent) {
parent = session.getContext().newPath(prefix + "/description", "Default NETCONF notification stream");
} else {
@@ -144,11 +155,11 @@ void notificationStreamList(sysrepo::Session& session, std::optional<libyang::Da
parent->newPath(prefix + "/access[encoding='xml']/location", streamsPrefix + "NETCONF/XML");
parent->newPath(prefix + "/access[encoding='json']/location", streamsPrefix + "NETCONF/JSON");
- if (replayEnabled) {
+ if (replayInfo.enabled) {
parent->newPath(prefix + "/replay-support", "true");
- if (globalEarliestNotification) {
- parent->newPath(prefix + "/replay-log-creation-time", libyang::yangTimeFormat(*globalEarliestNotification, libyang::TimezoneInterpretation::Local));
+ if (replayInfo.earliestNotification) {
+ parent->newPath(prefix + "/replay-log-creation-time", libyang::yangTimeFormat(*replayInfo.earliestNotification, libyang::TimezoneInterpretation::Local));
}
}
}
--
2.43.0
@@ -0,0 +1,53 @@
From 08458725211e707dec7bfebf7c5188e766136677 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Fri, 7 Feb 2025 17:34:04 +0100
Subject: [PATCH 25/44] sysrepo upstream API change: NULL output on RPCs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/8289
Change-Id: I8db21637246492b0f79d1adf7df1704df5173e39
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 2 +-
src/restconf/Server.cpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f3a9c0..cdd0eb4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -74,7 +74,7 @@ find_package(PkgConfig)
pkg_check_modules(nghttp2 REQUIRED IMPORTED_TARGET libnghttp2_asio>=0.0.90 libnghttp2)
find_package(Boost REQUIRED CONFIG COMPONENTS system thread)
-pkg_check_modules(SYSREPO-CPP REQUIRED IMPORTED_TARGET sysrepo-cpp>=4)
+pkg_check_modules(SYSREPO-CPP REQUIRED IMPORTED_TARGET sysrepo-cpp>=5)
pkg_check_modules(LIBYANG-CPP REQUIRED IMPORTED_TARGET libyang-cpp>=3)
pkg_check_modules(SYSTEMD IMPORTED_TARGET libsystemd)
pkg_check_modules(PAM REQUIRED IMPORTED_TARGET pam)
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
index 7c66ea4..daf23ed 100644
--- a/src/restconf/Server.cpp
+++ b/src/restconf/Server.cpp
@@ -462,13 +462,13 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, const std::c
auto rpcReply = requestCtx->sess.sendRPC(*rpcNode, timeout);
- if (rpcReply.immediateChildren().empty()) {
+ if (!rpcReply || rpcReply->immediateChildren().empty()) {
requestCtx->res.write_head(204, {CORS});
requestCtx->res.end();
return;
}
- auto responseNode = rpcReply.child();
+ auto responseNode = rpcReply->child();
responseNode->unlinkWithSiblings();
auto envelope = ctx.newOpaqueJSON(rpcNode->schema().module().name(), "output", std::nullopt);
--
2.43.0
@@ -0,0 +1,82 @@
From d69697a719781ef06ecb0545a58c2d055ca53c6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 3 Mar 2025 13:32:51 +0100
Subject: [PATCH 26/44] boost 1.87 support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
In Asio 1.33 (boost 1.87) some of the deprecated functionalities were
removed [1]. For rousette there are two changes that needed to be
addressed:
* A removed include in clock.cpp. But actually, we do not need that
header at all.
* boost::asio::io_service is no longer around, it was actually renamed
to boost::asio::io_context a while ago. Its post() method is no
longer around as well, it was deprecated in favour of post()
function [2].
This function is there since boost 1.66, so let's set minimal boost
version.
A bigger problem is that our dependency nghttp2-asio seems to be a dead
project. At the time of writing this, there are no patches for more than
3 years. However, we are not the only consumers of that project and
somebody else already took care of that before us [3,4].
[1] https://www.boost.org/doc/libs/1_87_0/doc/html/boost_asio/history.html
[2] https://live.boost.org/doc/libs/1_86_0/doc/html/boost_asio/reference/io_context/post.html
[3] https://github.com/nghttp2/nghttp2-asio/issues/23
[3] https://github.com/microsoft/vcpkg/commit/8eecddf7f18792d41c58a404604eed7f87b4b462
Change-Id: Ia59bb06e5f8ed222aa6e9f1c9b3947b05afeb9ec
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
CMakeLists.txt | 4 ++--
src/clock.cpp | 1 -
src/http/EventStream.cpp | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cdd0eb4..ca41ef3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,8 +71,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
find_package(spdlog REQUIRED)
find_package(date REQUIRED) # FIXME: Remove when we have STL with __cpp_lib_chrono >= 201907 (gcc 14)
find_package(PkgConfig)
-pkg_check_modules(nghttp2 REQUIRED IMPORTED_TARGET libnghttp2_asio>=0.0.90 libnghttp2)
-find_package(Boost REQUIRED CONFIG COMPONENTS system thread)
+pkg_check_modules(nghttp2 REQUIRED IMPORTED_TARGET libnghttp2_asio>=0.0.90 libnghttp2) # To compile under boost 1.87 you have to patch nghttp2-asio using https://github.com/nghttp2/nghttp2-asio/issues/23
+find_package(Boost 1.66 REQUIRED CONFIG COMPONENTS system thread)
pkg_check_modules(SYSREPO-CPP REQUIRED IMPORTED_TARGET sysrepo-cpp>=5)
pkg_check_modules(LIBYANG-CPP REQUIRED IMPORTED_TARGET libyang-cpp>=3)
diff --git a/src/clock.cpp b/src/clock.cpp
index 16a49b2..7ac6c3e 100644
--- a/src/clock.cpp
+++ b/src/clock.cpp
@@ -5,7 +5,6 @@
*
*/
-#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <chrono>
#include <nghttp2/asio_http2_server.h>
diff --git a/src/http/EventStream.cpp b/src/http/EventStream.cpp
index 34038f4..6c765c5 100644
--- a/src/http/EventStream.cpp
+++ b/src/http/EventStream.cpp
@@ -117,6 +117,6 @@ void EventStream::enqueue(const std::string& what)
spdlog::trace("{}: new event, ∑ queue size = {}", peer, len);
queue.push_back(buf);
state = HasEvents;
- res.io_service().post([&res = this->res]() { res.resume(); });
+ boost::asio::post(res.io_service(), [&res = this->res]() { res.resume(); });
}
}
--
2.43.0
@@ -0,0 +1,196 @@
From 97ceef119c900c37bbaa27860c3b43cfa6d69f95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 13 Jan 2025 13:01:07 +0100
Subject: [PATCH 27/44] restconf: refactor uri parser for stream URIs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
This is a preparation for the upcoming patch that will add support for
subscribed streams. I will use boost spirit x3 parser to parse such
URIs so I need to refactor the existing parser, which is not really a
parser, but we only match for the two known URIs.
Change-Id: Ib76973cd967fc3e9558ceb6be8f51239ce4c5ef3
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
src/restconf/Server.cpp | 15 +--------------
src/restconf/uri.cpp | 36 +++++++++++++++++++++++++++---------
src/restconf/uri.h | 11 ++++++-----
src/restconf/uri_impl.h | 2 ++
tests/uri-parser.cpp | 4 ++--
5 files changed, 38 insertions(+), 30 deletions(-)
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
index daf23ed..d356f7e 100644
--- a/src/restconf/Server.cpp
+++ b/src/restconf/Server.cpp
@@ -874,7 +874,6 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
server->handle(netconfStreamRoot, [this, conn](const auto& req, const auto& res) mutable {
auto sess = conn.sessionStart();
- libyang::DataFormat dataFormat;
std::optional<std::string> xpathFilter;
std::optional<sysrepo::NotificationTimeStamp> startTime;
std::optional<sysrepo::NotificationTimeStamp> stopTime;
@@ -890,18 +889,6 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
auto streamRequest = asRestconfStreamRequest(req.method(), req.uri().path, req.uri().raw_query);
- switch(streamRequest.type) {
- case RestconfStreamRequest::Type::NetconfNotificationJSON:
- dataFormat = libyang::DataFormat::JSON;
- break;
- case RestconfStreamRequest::Type::NetconfNotificationXML:
- dataFormat = libyang::DataFormat::XML;
- break;
- default:
- // GCC 14 complains about uninitialized variable, but asRestconfStreamRequest() would have thrown
- __builtin_unreachable();
- }
-
if (auto it = streamRequest.queryParams.find("filter"); it != streamRequest.queryParams.end()) {
xpathFilter = std::get<std::string>(it->second);
}
@@ -916,7 +903,7 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
// The signal is constructed outside NotificationStream class because it is required to be passed to
// NotificationStream's parent (EventStream) constructor where it already must be constructed
// Yes, this is a hack.
- auto client = std::make_shared<NotificationStream>(req, res, std::make_shared<rousette::http::EventStream::Signal>(), sess, dataFormat, xpathFilter, startTime, stopTime);
+ auto client = std::make_shared<NotificationStream>(req, res, std::make_shared<rousette::http::EventStream::Signal>(), sess, streamRequest.type.encoding, xpathFilter, startTime, stopTime);
client->activate();
} catch (const auth::Error& e) {
processAuthError(req, res, e, [&res]() {
diff --git a/src/restconf/uri.cpp b/src/restconf/uri.cpp
index da1e3a5..e95d70e 100644
--- a/src/restconf/uri.cpp
+++ b/src/restconf/uri.cpp
@@ -57,6 +57,13 @@ const auto resources = x3::rule<class resources, URIPath>{"resources"} =
((x3::lit("/") | x3::eps) /* /restconf/ and /restconf */ >> x3::attr(URIPrefix{URIPrefix::Type::RestconfRoot}) >> x3::attr(std::vector<PathSegment>{}));
const auto uriGrammar = x3::rule<class grammar, URIPath>{"grammar"} = x3::lit("/restconf") >> resources;
+
+const auto netconfStream = x3::rule<class netconfStream, RestconfStreamRequest::NetconfStream>{"netconfStream"} =
+ x3::lit("/NETCONF") >>
+ ((x3::lit("/XML") >> x3::attr(libyang::DataFormat::XML)) |
+ (x3::lit("/JSON") >> x3::attr(libyang::DataFormat::JSON)));
+const auto streamUriGrammar = x3::rule<class grammar, RestconfStreamRequest::NetconfStream>{"streamsGrammar"} = x3::lit("/streams") >> netconfStream;
+
// clang-format on
}
@@ -197,6 +204,17 @@ std::optional<queryParams::QueryParams> parseQueryParams(const std::string& quer
return ret;
}
+std::optional<RestconfStreamRequest::NetconfStream> parseStreamUri(const std::string& uriPath)
+{
+ std::optional<RestconfStreamRequest::NetconfStream> ret;
+
+ if (!x3::parse(std::begin(uriPath), std::end(uriPath), streamUriGrammar >> x3::eoi, ret)) {
+ return std::nullopt;
+ }
+
+ return ret;
+}
+
URIPrefix::URIPrefix()
: resourceType(URIPrefix::Type::BasicRestconfData)
{
@@ -637,20 +655,20 @@ std::optional<std::variant<libyang::Module, libyang::SubmoduleParsed>> asYangMod
return std::nullopt;
}
-RestconfStreamRequest asRestconfStreamRequest(const std::string& httpMethod, const std::string& uriPath, const std::string& uriQueryString)
+RestconfStreamRequest::NetconfStream::NetconfStream() = default;
+RestconfStreamRequest::NetconfStream::NetconfStream(const libyang::DataFormat& encoding)
+ : encoding(encoding)
{
- static const auto netconfStreamRoot = "/streams/NETCONF/";
- RestconfStreamRequest::Type type;
+}
+RestconfStreamRequest asRestconfStreamRequest(const std::string& httpMethod, const std::string& uriPath, const std::string& uriQueryString)
+{
if (httpMethod != "GET" && httpMethod != "HEAD") {
throw ErrorResponse(405, "application", "operation-not-supported", "Method not allowed.");
}
- if (uriPath == netconfStreamRoot + "XML"s) {
- type = RestconfStreamRequest::Type::NetconfNotificationXML;
- } else if (uriPath == netconfStreamRoot + "JSON"s) {
- type = RestconfStreamRequest::Type::NetconfNotificationJSON;
- } else {
+ auto type = impl::parseStreamUri(uriPath);
+ if (!type) {
throw ErrorResponse(404, "application", "invalid-value", "Invalid stream");
}
@@ -661,7 +679,7 @@ RestconfStreamRequest asRestconfStreamRequest(const std::string& httpMethod, con
validateQueryParametersForStream(*queryParameters);
- return {type, *queryParameters};
+ return {*type, *queryParameters};
}
/** @brief Returns a set of allowed HTTP methods for given URI. Usable for the 'allow' header */
diff --git a/src/restconf/uri.h b/src/restconf/uri.h
index f6df724..6f1f69f 100644
--- a/src/restconf/uri.h
+++ b/src/restconf/uri.h
@@ -197,11 +197,12 @@ struct RestconfRequest {
};
struct RestconfStreamRequest {
- enum class Type {
- NetconfNotificationJSON,
- NetconfNotificationXML,
- };
- Type type;
+ struct NetconfStream {
+ libyang::DataFormat encoding;
+
+ NetconfStream();
+ NetconfStream(const libyang::DataFormat& encoding);
+ } type;
queryParams::QueryParams queryParams;
};
diff --git a/src/restconf/uri_impl.h b/src/restconf/uri_impl.h
index 2bcdb3f..00b22f6 100644
--- a/src/restconf/uri_impl.h
+++ b/src/restconf/uri_impl.h
@@ -66,6 +66,8 @@ BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::impl::YangModule, name, revision);
BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::PathSegment, apiIdent, keys);
BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::ApiIdentifier, prefix, identifier);
+BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::RestconfStreamRequest::NetconfStream, encoding);
+
BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::queryParams::fields::ParenExpr, lhs, rhs);
BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::queryParams::fields::SlashExpr, lhs, rhs);
BOOST_FUSION_ADAPT_STRUCT(rousette::restconf::queryParams::fields::SemiExpr, lhs, rhs);
diff --git a/tests/uri-parser.cpp b/tests/uri-parser.cpp
index fd5dd8b..53d1fbb 100644
--- a/tests/uri-parser.cpp
+++ b/tests/uri-parser.cpp
@@ -1072,13 +1072,13 @@ TEST_CASE("URI path parser")
{
auto [type, queryParams] = asRestconfStreamRequest("GET", "/streams/NETCONF/XML", "");
- REQUIRE(type == RestconfStreamRequest::Type::NetconfNotificationXML);
+ REQUIRE(type.encoding == libyang::DataFormat::XML);
REQUIRE(queryParams.empty());
}
{
auto [type, queryParams] = asRestconfStreamRequest("GET", "/streams/NETCONF/JSON", "");
- REQUIRE(type == RestconfStreamRequest::Type::NetconfNotificationJSON);
+ REQUIRE(type.encoding == libyang::DataFormat::JSON);
REQUIRE(queryParams.empty());
}
--
2.43.0
@@ -0,0 +1,54 @@
From cc815dac4ea17ccb09a0481ad82745a194efe95f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
Date: Mon, 27 Jan 2025 19:17:07 +0100
Subject: [PATCH 28/44] server: prepare checking if yang features are enabled
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
We are not requiring any now, but next commits will need it. I am
splitting this into a separate commit for clarity.
Change-Id: I0a8874b55b21d5ed6c7222f0c36a36c3c5ff52c5
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
src/restconf/Server.cpp | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
index d356f7e..55e504a 100644
--- a/src/restconf/Server.cpp
+++ b/src/restconf/Server.cpp
@@ -817,14 +817,20 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
, server{std::make_unique<nghttp2::asio_http2::server::http2>()}
, dwdmEvents{std::make_unique<sr::OpticalEvents>(conn.sessionStart())}
{
- for (const auto& [module, version] : {
- std::pair<std::string, std::string>{"ietf-restconf", "2017-01-26"},
- {"ietf-restconf-monitoring", "2017-01-26"},
- {"ietf-netconf", ""},
- {"ietf-yang-library", "2019-01-04"},
- {"ietf-yang-patch", "2017-02-22"},
- }) {
- if (!conn.sessionStart().getContext().getModuleImplemented(module)) {
+ for (const auto& [module, version, features] : {
+ std::tuple<std::string, std::string, std::vector<std::string>>{"ietf-restconf", "2017-01-26", {}},
+ {"ietf-restconf-monitoring", "2017-01-26", {}},
+ {"ietf-netconf", "", {}},
+ {"ietf-yang-library", "2019-01-04", {}},
+ {"ietf-yang-patch", "2017-02-22", {}},
+ }) {
+ if (auto mod = conn.sessionStart().getContext().getModuleImplemented(module)) {
+ for (const auto& feature : features) {
+ if (!mod->featureEnabled(feature)) {
+ throw std::runtime_error("Module "s + module + "@" + version + " does not implement feature " + feature);
+ }
+ }
+ } else {
throw std::runtime_error("Module "s + module + "@" + version + " is not implemented in sysrepo");
}
}
--
2.43.0
@@ -0,0 +1,54 @@
From f45d7cab63431c94a4db859b07ea6f503214ebaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Thu, 13 Mar 2025 17:10:17 +0100
Subject: [PATCH 29/44] tests: refactor default handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires
...so that a followup commit which uses
libyang::PrintFlags::KeepEmptyCont introduces less noise.
Change-Id: I587cf8a5fc0e87b37f4bb91a74d848f58b61e336
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
tests/restconf-defaults.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tests/restconf-defaults.cpp b/tests/restconf-defaults.cpp
index dd8b4da..d5c6004 100644
--- a/tests/restconf-defaults.cpp
+++ b/tests/restconf-defaults.cpp
@@ -32,7 +32,7 @@ TEST_CASE("default handling")
auto server = rousette::restconf::Server{srConn, SERVER_ADDRESS, SERVER_PORT};
// default value of /example:a/b/c/enabled is implicitly set so it should not be printed
- REQUIRE(get(RESTCONF_DATA_ROOT "/example:a", {}) == Response{200, jsonHeaders, R"({
+ REQUIRE(get(RESTCONF_DATA_ROOT "/example:a/b/c", {}) == Response{200, jsonHeaders, R"({
}
)"});
@@ -72,7 +72,7 @@ TEST_CASE("default handling")
)"});
// default value is explicitly set so it should be printed
- REQUIRE(get(RESTCONF_DATA_ROOT "/example:a", {}) == Response{200, jsonHeaders, R"({
+ REQUIRE(get(RESTCONF_DATA_ROOT "/example:a/b/c", {}) == Response{200, jsonHeaders, R"({
"example:a": {
"b": {
"c": {
@@ -86,8 +86,8 @@ TEST_CASE("default handling")
// RFC 6243, sec. 2.3.3: A valid 'delete' operation attribute for a data node that has been set by a client to its schema default value MUST succeed.
REQUIRE(httpDelete(RESTCONF_DATA_ROOT "/example:a/b/c/enabled", {AUTH_ROOT}) == Response{204, noContentTypeHeaders, ""});
- // default value is implicitly set so it should be printed
- REQUIRE(get(RESTCONF_DATA_ROOT "/example:a", {}) == Response{200, jsonHeaders, R"({
+ // default value is only there implicitly, so it should *not* be printed
+ REQUIRE(get(RESTCONF_DATA_ROOT "/example:a/b/c", {}) == Response{200, jsonHeaders, R"({
}
)"});
--
2.43.0

Some files were not shown because too many files have changed in this diff Show More