Merge pull request #1198 from kernelkit/misc

Mixed bag of fixes mostly for RPi4

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2025-10-14 09:20:44 +02:00
committed by GitHub
14 changed files with 517 additions and 142 deletions
+1
View File
@@ -56,6 +56,7 @@ CONFIG_JUMP_LABEL=y
# CONFIG_GCC_PLUGINS is not set # CONFIG_GCC_PLUGINS is not set
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
# CONFIG_COMPAT_BRK is not set # CONFIG_COMPAT_BRK is not set
CONFIG_KSM=y CONFIG_KSM=y
+138
View File
@@ -51,11 +51,140 @@ factory_reset()
sync sync
} }
is_rpi()
{
[ -r /sys/firmware/devicetree/base/model ] || return 1
model=$(cat /sys/firmware/devicetree/base/model 2>/dev/null | tr -d '\0')
echo "$model" | grep -q "^Raspberry Pi"
}
wait_mmc()
{
# Try up to 50 times with 0.2s sleep = 10 second timeout
for _ in $(seq 50); do
if ls /dev/mmcblk* >/dev/null 2>&1; then
logger $opt -p user.notice -t "$nm" "MMC device available after delay"
return 0
fi
sleep .2
done
logger $opt -p user.warn -t "$nm" "Timeout waiting for MMC device"
return 1
}
# This early on we don't have the luxury of /dev/disk/by-label/$1
find_partition_by_label()
{
label="$1"
for diskpath in /sys/class/block/*; do
devname=$(basename "$diskpath")
[ -f "$diskpath/partition" ] && continue
disk="/dev/$devname"
result=$(sgdisk -p "$disk" 2>/dev/null | awk -v label="$label" -v devname="$devname" '
/^ *[0-9]/ {
if ($7 == label) {
if (devname ~ /^(mmcblk|nvme|loop)/) {
print devname "p" $1
} else {
print devname $1
}
exit 0
}
}
')
if [ -n "$result" ]; then
echo "$result"
return 0
fi
done
return 1
}
# Expand the given partition to fill up the rest of storage (sdcard)
resize_by_label()
{
label="$1"
devname=$(find_partition_by_label "$label")
if [ -z "$devname" ]; then
logger $opt -p user.err -t "$nm" "Label \"$label\" not found"
return 1
fi
part="/dev/$devname"
diskname=$(basename "$(readlink -f "/sys/class/block/$devname/..")")
disk="/dev/$diskname"
partnum="${devname##*[^0-9]}"
logger $opt -p user.notice -t "$nm" "Found partition $part (partition $partnum on $disk)"
start=$(sgdisk -i "$partnum" "$disk" 2>/dev/null | grep "First sector:" | awk '{print $3}')
if [ -z "$start" ]; then
logger $opt -p user.err -t "$nm" "Could not determine start sector for partition $partnum"
return 1
fi
printf "\r\033[K[ ⋯ ] Resizing /var partition on sdcard, please wait ..." > /dev/console
logger $opt -p user.notice -t "$nm" "Expanding partition $partnum from sector $start to end of disk"
if ! sgdisk -e "$disk" 2>&1 | logger $opt -p user.notice -t "$nm"; then
logger $opt -p user.warn -t "$nm" "Failed expanding GPT on $disk"
return 1
fi
if ! sgdisk -d "$partnum" "$disk" >/dev/null 2>&1; then
logger $opt -p user.warn -t "$nm" "Failed deleting partition $partnum on $disk"
return 1
fi
if ! sgdisk -n "$partnum:$start:0" "$disk" >/dev/null 2>&1; then
logger $opt -p user.warn -t "$nm" "Failed recreating partition $partnum on $disk"
return 1
fi
if ! sgdisk -t "$partnum:8300" "$disk" >/dev/null 2>&1; then
logger $opt -p user.warn -t "$nm" "Failed setting partition type on $disk"
return 1
fi
if ! sgdisk -c "$partnum:$label" "$disk" >/dev/null 2>&1; then
logger $opt -p user.warn -t "$nm" "Failed setting partition label on $disk"
return 1
fi
logger $opt -p user.notice -t "$nm" "Partition table updated on $disk"
partprobe "$disk" 2>/dev/null
logger $opt -p user.notice -t "$nm" "Resizing filesystem on $part"
if ! resize2fs "$part" 2>&1 | logger $opt -p user.notice -t "$nm"; then
logger $opt -p user.warn -t "$nm" "Failed resizing filesystem on $part"
return 1
fi
tune2fs -O resize_inode "$part" 2>/dev/null
printf "\r\033[K[ \033[32mOK\033[0m ] Resizing /var partition on sdcard, done. Rebooting ...\n" > /dev/console
logger $opt -p user.notice -t "$nm" "Partition expanded, rebooting to complete filesystem resize"
reboot -f
}
mount_rw() mount_rw()
{ {
# If something is already setup, leave it be. # If something is already setup, leave it be.
mountpoint -q "/$1" && return 0 mountpoint -q "/$1" && return 0
if [ "$1" = "var" ]; then
if is_rpi && [ ! -e /mnt/aux/resized ] ; then
touch /mnt/aux/resized
resize_by_label "$1"
fi
fi
# TODO: Also look for UBI partitions # TODO: Also look for UBI partitions
mount LABEL="$1" 2>/dev/null && return 0 mount LABEL="$1" 2>/dev/null && return 0
@@ -103,6 +232,15 @@ if ! logger -? |grep -q "Log to kernel"; then
opt="-c" opt="-c"
fi fi
# On Raspberry Pi, MMC controller may probe slowly, in particular if we
# netboot (ram load) the devcice wait for it
if is_rpi && ! ls /dev/mmcblk* >/dev/null 2>&1; then
wait_mmc
fi
# The aux partition must be mounted before everything else since it's used
# for internal bookkeeping.
if ! mount_rw aux >/dev/null 2>&1; then if ! mount_rw aux >/dev/null 2>&1; then
logger $opt -p user.warn -t "$nm" \ logger $opt -p user.warn -t "$nm" \
"No auxiliary partition found, software updates not supported." "No auxiliary partition found, software updates not supported."
+5
View File
@@ -11,9 +11,13 @@ All notable changes to the project are documented in this file.
- Upgrade Linux kernel to 6.12.50 (LTS) - Upgrade Linux kernel to 6.12.50 (LTS)
- Extend NETCONF and RESTCONF scripting documentation with operational - Extend NETCONF and RESTCONF scripting documentation with operational
data examples, discovery patterns, and common workflow examples, issue #1156 data examples, discovery patterns, and common workflow examples, issue #1156
- Initial support for a zone-based firewall, based on `firewalld`, issue #448
- Automatically expand `/var` partition on SD card at first boot on RPi
### Fixes ### Fixes
- Fix #1194: CLI `text-editor` command does not do proper input sanitation
- Fix #1197: RPi4 no longer boots after BPi-R3 merge, introduced in v25.09
[v25.09.0][] - 2025-09-30 [v25.09.0][] - 2025-09-30
------------------------- -------------------------
@@ -1656,6 +1660,7 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
[buildroot]: https://buildroot.org/ [buildroot]: https://buildroot.org/
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v25.09.0...HEAD [UNRELEASED]: https://github.com/kernelkit/infix/compare/v25.09.0...HEAD
[v25.10.0]: https://github.com/kernelkit/infix/compare/v25.09.0...v26.10.0
[v25.09.0]: https://github.com/kernelkit/infix/compare/v25.08.0...v26.09.0 [v25.09.0]: https://github.com/kernelkit/infix/compare/v25.08.0...v26.09.0
[v25.08.0]: https://github.com/kernelkit/infix/compare/v25.06.1...v26.08.0 [v25.08.0]: https://github.com/kernelkit/infix/compare/v25.06.1...v26.08.0
[v25.06.0]: https://github.com/kernelkit/infix/compare/v25.05.1...v26.06.0 [v25.06.0]: https://github.com/kernelkit/infix/compare/v25.05.1...v26.06.0
-72
View File
@@ -1,72 +0,0 @@
* TODO Add support for firewall
- [X] All "implicit" policies in zones are now policies: intra- and inter-zone policies
- [X] Add locked rules for implicit drop/reject policy as last rule in policy (ANY, ANY)
- [X] Firewall logs should show IN=iface (IIF) before SOURCE
- [X] Interfaces are not defaulting to the default zone, must handle bridge
ports and changes to enslavement, so regenerate every time is a must!
- [ ] firewalld helpers -- possibly for conntrack, e.g., ftp
- [ ] With =modprobe br_netfilter= firewalld would see *all* traffic, but there are
issues, <https://github.com/firewalld/firewalld/issues/1236>, and limits to what
seem to be possible atm. You may also need to enable these callbacks:
=echo 1 | sudo tee /proc/sys/net/bridge/bridge-nf-call-iptables=
=echo 1 | sudo tee /proc/sys/net/bridge/bridge-nf-call-ip6tables=
=echo 1 | sudo tee /proc/sys/net/bridge/bridge-nf-call-arptables=
- [X] Add missing upper to port forward since port ranges are supported, see services!
- [X] =[do] show firewall= not available yet
- [X] Add RPC to pause firewall using =firewall-cmd --panic-on= and restart
firewall again with =firewall-cmd --panic-off=. The current state can
be queried using =firewall-cmd --query-panic=, which returns =yes=
- [X] Remove debug log messages!
- [X] Add "Log Messages" section to =show firewall= when =LogDenied ≠ off=
- [ ] Investigate filtering out firewall log messages from other log files
- [1/2] Rename policy->policy to policy->action, and replace allow->forward
- [X] Rename zone->sources to networks
- [X] A zone's action is for ingress, clarify this if missing!
- [X] Any services/ports listed in a zone with policy:accept are a NO-OP
- [X] =firwall-cmd --reload= takes fooooorever! :-(
- [X] If forwarding is disabled in a zone then the zone matrix should
show deny for the same zone-to-zone communication
- [X] We should show the implicit rules for communicating with the HOST
- [X] Investigate "padlock" on built-in policys (and zones?) and expose more?
- [X] Document established,related somewhere, fixed/padlocked policy? Also,
document why this is a good idea to always have enabled. See RH docs.
- [ ] Podman published ports, <https://firewalld.org/2024/11/strict-forward-ports>
- [ ] Software fastpath <https://firewalld.org/2023/05/nftables-flowtable>
- +[ ] Allow overriding/editing immutable policies and zones+
- [X] Add tests: basic (end device), wan-lan, wan-lan-dmz, +hammer (stress)+
- [X] Add documentation
- See <https://docs.rockylinux.org/guides/security/firewalld-beginners/>
- Add some tool tips: nc, nmap, ping, and socat to stress the firewall
- [X] Fix inference so we can remove defaults from factory-config!
- [X] Add iperf service
- [X] Add nftables ownership=yes setting, introduced in later firewalld versions
- [ ] Investigate fail2ban integration with firewalld, for more info, see:
https://github.com/firewalld/firewalld/issues/1466#issuecomment-2773130569
- [ ] Update screenshots for documentation
- [ ] Review both cli-pretty and yanger code
- [ ] Review default-zone handling (needed?)
- [ ] Clean up =INFER_POLICY= ifdefs
- [ ] Revisit built-in fallback zones (public, block, drop)
* TODO doc: User Guide
- Feature set and scope, e.g.
- Device discovery: LLDP, mDNS-SD how do they work, interfacing with Windows/macOS/Linux
- Network redundancy protocols: STP/RSTP, MRP
- Configuring the system; using ifupdown2, enabling/disabling services
- Diagnosing the system; using rmon, port mirroring, debugging services, searching logs
- Limitations, e.g., PRP/HSR or IEEE 802.1CB will not be possible to support
- Tips & Trix
* TODO document how to set up passwordless SSH
* TODO add setup wizard, based on pdmenu
- setup-port script to tweak ethtool settings
- setup-iface script to configure a layer-3 interface
- setup-bridge script that creates a new bridge with config from cmdline
- setup-firewall script that can do basic firewall rules and masquerading
* TODO split out qemu Config.in to a "make run-menuconfing"
* TODO rename qemu/ to run/, perhaps?
* TODO ship qemu/* with output/images/ for stand-alone runs of older builds
+104 -44
View File
@@ -16,23 +16,79 @@ To simplify RESTCONF operations, create a `curl.sh` wrapper script:
```bash ```bash
#!/bin/sh #!/bin/sh
# RESTCONF CLI wrapper for curl
AUTH=${AUTH:-admin:admin} # Show usage and exit
usage()
{
cat <<-EOF >&2
Usage: $0 [-h HOST] [-d DATASTORE] [-u USER:PASS] METHOD PATH [CURL_ARGS...]
Options:
-h HOST Target host (default: infix.local)
-d DS Datastore: running, operational, startup (default: running)
-u CREDS Credentials as user:pass (default: admin:admin)
Methods: GET, POST, PUT, PATCH, DELETE
EOF
exit "$1"
}
# Default values
HOST=${HOST:-infix.local} HOST=${HOST:-infix.local}
DATASTORE=running
AUTH=admin:admin
method=$1 # Parse options
path=$2 while getopts "h:d:u:" opt; do
case $opt in
h) HOST="$OPTARG" ;;
d) DATASTORE="$OPTARG" ;;
u) AUTH="$OPTARG" ;;
*) usage 1 ;;
esac
done
shift $((OPTIND - 1))
# Validate required arguments
if [ $# -lt 2 ]; then
echo "Error: METHOD and PATH are required" >&2
usage 1
fi
METHOD=$1
PATH=$2
shift 2 shift 2
set -x # Ensure PATH starts with /
exec curl \ case "$PATH" in
--insecure \ /*) ;;
--user ${AUTH} \ *) PATH="/$PATH" ;;
--request ${method} \ esac
--header "Content-Type: application/yang-data+json" \
--header "Accept: application/yang-data+json" \ # Build URL based on datastore
"$@" \ case "$DATASTORE" in
https://${HOST}/restconf/ds/ietf-datastores:${path} running|startup)
URL="https://${HOST}/restconf/data${PATH}"
;;
operational)
URL="https://${HOST}/restconf/data${PATH}"
;;
*)
echo "Error: Invalid datastore '$DATASTORE'. Use: running, operational, or startup" >&2
exit 1
;;
esac
# Execute curl with all remaining arguments passed through
exec /usr/bin/curl \
--insecure \
--user "${AUTH}" \
--request "${METHOD}" \
--header "Content-Type: application/yang-data+json" \
--header "Accept: application/yang-data+json" \
"$@" \
"${URL}"
``` ```
Make it executable: Make it executable:
@@ -41,12 +97,16 @@ Make it executable:
~$ chmod +x curl.sh ~$ chmod +x curl.sh
``` ```
This wrapper handles authentication, headers, and the base URL construction, This wrapper handles authentication, headers, SSL certificates, and URL
making commands much cleaner. You can override defaults with environment construction, making commands much cleaner. You can override defaults with
variables: command-line options or environment variables:
```bash ```bash
~$ HOST=192.168.1.10 AUTH=admin:secret ./curl.sh GET running/... # Using command-line options
~$ ./curl.sh -h 192.168.1.10 -d operational -u admin:secret GET /ietf-interfaces:interfaces
# Using environment variables
~$ HOST=192.168.1.10 ./curl.sh GET /ietf-system:system
``` ```
The examples below show both raw `curl` commands and the equivalent using The examples below show both raw `curl` commands and the equivalent using
@@ -63,7 +123,7 @@ practical workflows.
**List all interface names:** **List all interface names:**
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces 2>/dev/null | jq -r '.["ietf-interfaces:interfaces"]["interface"][].name' ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces 2>/dev/null | jq -r '.["ietf-interfaces:interfaces"]["interface"][].name'
lo lo
e0 e0
e1 e1
@@ -89,7 +149,7 @@ This returns all supported YANG modules, revisions, and features.
Useful for exploration or backup: Useful for exploration or backup:
```bash ```bash
~$ ./curl.sh example.local GET running -o backup.json ~$ ./curl.sh -h example.local GET / -o backup.json
``` ```
### Common Workflow Patterns ### Common Workflow Patterns
@@ -99,21 +159,21 @@ Useful for exploration or backup:
Get all interfaces with IPs and search: Get all interfaces with IPs and search:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces 2>/dev/null \ ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces 2>/dev/null \
| jq -r '.["ietf-interfaces:interfaces"]["interface"][] | select(.["ietf-ip:ipv4"]["address"][]?.ip == "192.168.1.100") | .name' | jq -r '.["ietf-interfaces:interfaces"]["interface"][] | select(.["ietf-ip:ipv4"]["address"][]?.ip == "192.168.1.100") | .name'
``` ```
#### Pattern 2: List all interfaces that are down #### Pattern 2: List all interfaces that are down
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces 2>/dev/null \ ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces 2>/dev/null \
| jq -r '.["ietf-interfaces:interfaces"]["interface"][] | select(.["oper-status"] == "down") | .name' | jq -r '.["ietf-interfaces:interfaces"]["interface"][] | select(.["oper-status"] == "down") | .name'
``` ```
#### Pattern 3: Get statistics for all interfaces #### Pattern 3: Get statistics for all interfaces
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces 2>/dev/null \ ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces 2>/dev/null \
| jq -r '.["ietf-interfaces:interfaces"]["interface"][] | "\(.name): RX \(.statistics["in-octets"]) TX \(.statistics["out-octets"])"' | jq -r '.["ietf-interfaces:interfaces"]["interface"][] | "\(.name): RX \(.statistics["in-octets"]) TX \(.statistics["out-octets"])"'
``` ```
@@ -128,7 +188,7 @@ e1: RX 0 TX 0
#### Pattern 4: Check if interface exists before configuring #### Pattern 4: Check if interface exists before configuring
```bash ```bash
~$ if ./curl.sh example.local GET running/ietf-interfaces:interfaces/interface=eth0 2>/dev/null | grep -q "ietf-interfaces:interface"; then ~$ if ./curl.sh -h example.local GET /ietf-interfaces:interfaces/interface=eth0 2>/dev/null | grep -q "ietf-interfaces:interface"; then
echo "Interface eth0 exists" echo "Interface eth0 exists"
else else
echo "Interface eth0 not found" echo "Interface eth0 not found"
@@ -157,7 +217,7 @@ Example of fetching JSON configuration data:
**Using curl.sh:** **Using curl.sh:**
```bash ```bash
~$ ./curl.sh example.local GET running/ietf-system:system/hostname ~$ ./curl.sh -h example.local GET /ietf-system:system/hostname
{ {
"ietf-system:system": { "ietf-system:system": {
"hostname": "foo" "hostname": "foo"
@@ -181,7 +241,7 @@ Example of updating configuration with inline JSON data:
**Using curl.sh:** **Using curl.sh:**
```bash ```bash
~$ ./curl.sh example.local PATCH running/ietf-system:system \ ~$ ./curl.sh -h example.local PATCH /ietf-system:system \
-d '{"ietf-system:system":{"hostname":"bar"}}' -d '{"ietf-system:system":{"hostname":"bar"}}'
``` ```
@@ -190,8 +250,8 @@ Example of updating configuration with inline JSON data:
Add an IP address to the loopback interface: Add an IP address to the loopback interface:
```bash ```bash
~$ ./curl.sh example.local POST \ ~$ ./curl.sh -h example.local POST \
running/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 \ /ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 \
-d '{ "prefix-length": 32 }' -d '{ "prefix-length": 32 }'
``` ```
@@ -200,8 +260,8 @@ Add an IP address to the loopback interface:
Remove an IP address from the loopback interface: Remove an IP address from the loopback interface:
```bash ```bash
~$ ./curl.sh example.local DELETE \ ~$ ./curl.sh -h example.local DELETE \
running/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 /ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254
``` ```
### Copy Running to Startup ### Copy Running to Startup
@@ -228,8 +288,8 @@ and then update startup with it:
**Using curl.sh:** **Using curl.sh:**
```bash ```bash
~$ ./curl.sh example.local GET running -o running-config.json ~$ ./curl.sh -h example.local GET / -o running-config.json
~$ ./curl.sh example.local PUT startup -d @running-config.json ~$ ./curl.sh -h example.local -d startup PUT / -d @running-config.json
``` ```
## Operational Data ## Operational Data
@@ -239,7 +299,7 @@ and then update startup with it:
Get the running configuration for the loopback interface: Get the running configuration for the loopback interface:
```bash ```bash
~$ ./curl.sh example.local GET running/ietf-interfaces:interfaces/interface=lo ~$ ./curl.sh -h example.local GET /ietf-interfaces:interfaces/interface=lo
``` ```
### Read Interface Operational State ### Read Interface Operational State
@@ -247,7 +307,7 @@ Get the running configuration for the loopback interface:
Get operational data (state, statistics, etc.) for an interface: Get operational data (state, statistics, etc.) for an interface:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces/interface=lo ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces/interface=lo
``` ```
This includes administrative and operational state, MAC address, MTU, and This includes administrative and operational state, MAC address, MTU, and
@@ -258,7 +318,7 @@ statistics counters.
Extract specific statistics using `jq`: Extract specific statistics using `jq`:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces/interface=eth0 2>/dev/null \ ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces/interface=eth0 2>/dev/null \
| jq -r '.["ietf-interfaces:interfaces"]["interface"][0]["statistics"]["in-octets"]' | jq -r '.["ietf-interfaces:interfaces"]["interface"][0]["statistics"]["in-octets"]'
``` ```
@@ -267,7 +327,7 @@ Extract specific statistics using `jq`:
Get operational data for all interfaces: Get operational data for all interfaces:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-interfaces:interfaces ~$ ./curl.sh -h example.local -d operational GET /ietf-interfaces:interfaces
``` ```
### Read Routing Table ### Read Routing Table
@@ -275,7 +335,7 @@ Get operational data for all interfaces:
Get the IPv4 routing table: Get the IPv4 routing table:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-routing:routing/ribs/rib=ipv4-default ~$ ./curl.sh -h example.local -d operational GET /ietf-routing:routing/ribs/rib=ipv4-default
``` ```
### Read OSPF State ### Read OSPF State
@@ -283,13 +343,13 @@ Get the IPv4 routing table:
Get OSPF operational data (neighbors, routes, etc.): Get OSPF operational data (neighbors, routes, etc.):
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-routing:routing/control-plane-protocols/control-plane-protocol=ietf-ospf:ospfv2,default ~$ ./curl.sh -h example.local -d operational GET /ietf-routing:routing/control-plane-protocols/control-plane-protocol=ietf-ospf:ospfv2,default
``` ```
Or get just the neighbor information: Or get just the neighbor information:
```bash ```bash
~$ ./curl.sh example.local GET operational/ietf-routing:routing/control-plane-protocols/control-plane-protocol=ietf-ospf:ospfv2,default/ietf-ospf:ospf/areas/area=0.0.0.0/interfaces ~$ ./curl.sh -h example.local -d operational GET /ietf-routing:routing/control-plane-protocols/control-plane-protocol=ietf-ospf:ospfv2,default/ietf-ospf:ospf/areas/area=0.0.0.0/interfaces
``` ```
## System Operations (RPCs) ## System Operations (RPCs)
@@ -345,22 +405,22 @@ Create a `Makefile` to simplify common operations:
HOST ?= infix.local HOST ?= infix.local
lo-running: lo-running:
./curl.sh $(HOST) GET running/ietf-interfaces:interfaces/interface=lo ./curl.sh -h $(HOST) GET /ietf-interfaces:interfaces/interface=lo
lo-operational: lo-operational:
./curl.sh $(HOST) GET operational/ietf-interfaces:interfaces/interface=lo ./curl.sh -h $(HOST) -d operational GET /ietf-interfaces:interfaces/interface=lo
lo-add-ip: lo-add-ip:
./curl.sh $(HOST) POST \ ./curl.sh -h $(HOST) POST \
running/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 \ /ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 \
-d '{ "prefix-length": 32 }' -d '{ "prefix-length": 32 }'
lo-del-ip: lo-del-ip:
./curl.sh $(HOST) DELETE \ ./curl.sh -h $(HOST) DELETE \
running/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 /ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254
%-stats: %-stats:
@./curl.sh $(HOST) GET operational/ietf-interfaces:interfaces/interface=$* 2>/dev/null \ @./curl.sh -h $(HOST) -d operational GET /ietf-interfaces:interfaces/interface=$* 2>/dev/null \
| jq -r '.["ietf-interfaces:interfaces"]["interface"][0]["statistics"]["in-octets"]' | jq -r '.["ietf-interfaces:interfaces"]["interface"][0]["statistics"]["in-octets"]'
%-monitor: %-monitor:
+1 -1
View File
@@ -28,7 +28,7 @@ define BANANA_PI_R3_LINUX_CONFIG_FIXUPS
$(call KCONFIG_SET_OPT,CONFIG_USB_XHCI_MTK,m) $(call KCONFIG_SET_OPT,CONFIG_USB_XHCI_MTK,m)
$(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_TPHY,m) $(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_TPHY,m)
$(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_XSPHY,m) $(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_XSPHY,m)
$(call KCONFIG_SET_OPT,CONFIG_REGULATOR_GPIO,m) $(call KCONFIG_SET_OPT,CONFIG_REGULATOR_GPIO,y)
$(call KCONFIG_SET_OPT,CONFIG_REGULATOR_MT6380,m) $(call KCONFIG_SET_OPT,CONFIG_REGULATOR_MT6380,m)
$(call KCONFIG_SET_OPT,CONFIG_PWM_MEDIATEK,m) $(call KCONFIG_SET_OPT,CONFIG_PWM_MEDIATEK,m)
$(call KCONFIG_SET_OPT,CONFIG_SENSORS_PWM_FAN,m) $(call KCONFIG_SET_OPT,CONFIG_SENSORS_PWM_FAN,m)
@@ -1,3 +1,5 @@
# The CONFIG_REGULATOR_GPIO=y is load bearing for booting the RPi4 from
# SD card, see regulator-sd-io-1v8 in bcm2711-rpi-4-b.dts for details.
define RASPBERRY_PI_4_LINUX_CONFIG_FIXUPS define RASPBERRY_PI_4_LINUX_CONFIG_FIXUPS
$(call KCONFIG_ENABLE_OPT,CONFIG_SOUND) $(call KCONFIG_ENABLE_OPT,CONFIG_SOUND)
$(call KCONFIG_ENABLE_OPT,CONFIG_SND) $(call KCONFIG_ENABLE_OPT,CONFIG_SND)
@@ -32,6 +34,7 @@ define RASPBERRY_PI_4_LINUX_CONFIG_FIXUPS
$(call KCONFIG_ENABLE_OPT,CONFIG_NET_VENDOR_BROADCOM) $(call KCONFIG_ENABLE_OPT,CONFIG_NET_VENDOR_BROADCOM)
$(call KCONFIG_SET_OPT,CONFIG_BCMGENET,m) $(call KCONFIG_SET_OPT,CONFIG_BCMGENET,m)
$(call KCONFIG_SET_OPT,CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY,m) $(call KCONFIG_SET_OPT,CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY,m)
$(call KCONFIG_SET_OPT,CONFIG_REGULATOR_GPIO,y)
$(call KCONFIG_ENABLE_OPT,CONFIG_COMMON_CLK_BCM2835) $(call KCONFIG_ENABLE_OPT,CONFIG_COMMON_CLK_BCM2835)
$(call KCONFIG_ENABLE_OPT,CONFIG_CLK_RASPBERRYPI) $(call KCONFIG_ENABLE_OPT,CONFIG_CLK_RASPBERRYPI)
$(call KCONFIG_ENABLE_OPT,CONFIG_DRM) $(call KCONFIG_ENABLE_OPT,CONFIG_DRM)
@@ -1,3 +1,3 @@
# Locally calculated # Locally calculated
sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE sha256 9d9d33b873917ca5d0bdcc47a36d2fd385971ab0c045d1472fcadf95ee5bcf5b LICENCE
sha256 a6fe769a8f24a065b274f4e0f5f1fec634b2aae5bdd586aa6f71fe60ca6b8a64 klish-plugin-sysrepo-30bc6294489807ea026abed20f94d1ad1583cc6b-git4.tar.gz sha256 cfe1064849a158f3eb9e82f12a709723115fc9bc4d30056e0e96ea0ba03672a2 klish-plugin-sysrepo-4e86a836c9b09a14c9625ea3d3b56b6578be4833-git4.tar.gz
@@ -4,7 +4,7 @@
# #
################################################################################ ################################################################################
KLISH_PLUGIN_SYSREPO_VERSION = 30bc6294489807ea026abed20f94d1ad1583cc6b KLISH_PLUGIN_SYSREPO_VERSION = 4e86a836c9b09a14c9625ea3d3b56b6578be4833
KLISH_PLUGIN_SYSREPO_SITE = https://github.com/kernelkit/klish-plugin-sysrepo.git KLISH_PLUGIN_SYSREPO_SITE = https://github.com/kernelkit/klish-plugin-sysrepo.git
#KLISH_PLUGIN_SYSREPO_VERSION = cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb #KLISH_PLUGIN_SYSREPO_VERSION = cdd3eb51a7f7ee0ed5bd925fa636061d3b1b85fb
#KLISH_PLUGIN_SYSREPO_SITE = https://src.libcode.org/pkun/klish-plugin-sysrepo.git #KLISH_PLUGIN_SYSREPO_SITE = https://src.libcode.org/pkun/klish-plugin-sysrepo.git
+9 -10
View File
@@ -1,4 +1,3 @@
image cfg.ext4 { image cfg.ext4 {
empty = true empty = true
temporary = true temporary = true
@@ -27,19 +26,19 @@ image #INFIX_ID##VERSION#-bpi-r3-sdcard.img {
partition bl2 { partition bl2 {
image = "bl2.img" image = "bl2.img"
offset = 1024s # 0x80000 = sector 1024 offset = 1024s # 0x80000 = sector 1024
size = 4M # 0x400000 size = 4M # 0x400000
bootable = true bootable = true
} }
# Factory/calibration data (sectors 9216-13311) # Factory/calibration data (sectors 9216-13311)
partition factory { partition factory {
offset = 4608K # 0x480000 offset = 4608K # 0x480000
size = 2M # 0x200000 size = 2M # 0x200000
} }
# FIP partition - BL31 + U-Boot (sectors 13312-17407) # FIP partition - BL31 + U-Boot (sectors 13312-17407)
partition fip { partition fip {
# partition-type = 0x83 # Linux filesystem # partition-type = 0x83 # Linux filesystem
image = "fip.bin" image = "fip.bin"
offset = 13312s offset = 13312s
size = 4096s size = 4096s
+2 -2
View File
@@ -48,14 +48,14 @@ image #INFIX_ID##VERSION#-rpi4-sdcard.img {
partition primary { partition primary {
partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4
bootable = true bootable = true
size = 200M size = 250M
image = "rootfs.squashfs" image = "rootfs.squashfs"
} }
partition secondary { partition secondary {
partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4
bootable = true bootable = true
size = 200M size = 250M
image = "rootfs.squashfs" image = "rootfs.squashfs"
} }
+173 -6
View File
@@ -1,6 +1,152 @@
#!/bin/sh #!/bin/sh
set -e set -e
usage()
{
cat <<EOF
Create Raspberry Pi 4 SD card image from build artifacts.
Usage:
$0 [OPTIONS]
Options:
-h This help text
-b boot-dir Path to bootloader build directory, default: O= or output/
-r root-dir Path to Linux rootfs.squashfs, default O= or output/
Description:
When called without arguments (from Buildroot), uses environment variables:
BINARIES_DIR, BUILD_DIR, BR2_EXTERNAL_INFIX_PATH, RELEASE, INFIX_ID
When called with arguments, sets up standalone mode and combines artifacts
from separate boot and rootfs sources.
Output:
The resulting SD card image is saved to boot-dir/images/*-sdcard.img
Examples:
# Using separate build directories:
$0 -b x-boot -r output
# Using a rootfs file directly:
$0 -b x-boot -r ~/Downloads/rootfs.squashfs
EOF
}
getconfig()
{
[ -f .config ] || return 1
grep "^$1=" .config | sed -e "s/$1=\"\?\([^\"]*\)\"\?/\1/"
}
find_build_dir()
{
# Check O= environment variable first
if [ -n "$O" ] && [ -f "$O/.config" ]; then
echo "$O"
return 0
fi
# Check output/ directory
if [ -f "output/.config" ]; then
echo "output"
return 0
fi
return 1
}
# Parse command line options
STANDALONE=0
while getopts "hb:r:" flag; do
case "${flag}" in
h) usage; exit 0;;
b) BOOT_DIR=${OPTARG}; STANDALONE=1;;
r) ROOT_DIR=${OPTARG}; STANDALONE=1;;
*) usage; exit 1;;
esac
done
# Standalone mode: set up environment from build directories
if [ "$STANDALONE" -eq 1 ] || [ $# -gt 0 ]; then
STANDALONE=1
# Find BR2_EXTERNAL_INFIX_PATH (current script is in src/board/raspberry-pi-4/)
SCRIPT_DIR=$(dirname "$0")
BR2_EXTERNAL_INFIX_PATH=$(cd "$SCRIPT_DIR/../../.." && pwd)
# Find boot directory if not specified (try common patterns)
if [ -z "$BOOT_DIR" ]; then
for dir in x-boot build-boot output-boot; do
if [ -f "$dir/.config" ]; then
BOOT_DIR="$dir"
break
fi
done
if [ -z "$BOOT_DIR" ]; then
BOOT_DIR=$(find_build_dir) || {
echo "Error: Could not find boot directory. Use -b option" >&2
exit 1
}
fi
fi
# Find rootfs if not specified
if [ -z "$ROOT_DIR" ]; then
ROOT_DIR=$(find_build_dir) || {
echo "Error: Could not find rootfs directory. Set O= or use -r option" >&2
exit 1
}
fi
# Set up environment variables (use BOOT_DIR as base)
export BINARIES_DIR="$BOOT_DIR/images"
export BUILD_DIR="$BOOT_DIR/build"
export BR2_EXTERNAL_INFIX_PATH
export RELEASE=${RELEASE:-""}
export INFIX_ID=${INFIX_ID:-"infix"}
# Add host tools to PATH (for genimage, etc.)
for dir in "$BOOT_DIR" "$ROOT_DIR"; do
if [ -d "$dir/host/bin" ]; then
export PATH="$dir/host/bin:$PATH"
break
fi
done
# Copy rootfs and partition images to boot directory
mkdir -p "$BINARIES_DIR"
if [ -f "$ROOT_DIR" ]; then
# Direct path to rootfs.squashfs file
echo "Copying rootfs from $ROOT_DIR to $BINARIES_DIR/rootfs.squashfs"
cp "$ROOT_DIR" "$BINARIES_DIR/rootfs.squashfs"
elif [ -f "$ROOT_DIR/images/rootfs.squashfs" ]; then
# Build directory with images/ - copy rootfs and partition images
echo "Copying rootfs and partitions from $ROOT_DIR/images/ to $BINARIES_DIR/"
cp "$ROOT_DIR/images/rootfs.squashfs" "$BINARIES_DIR/"
# Copy partition images (aux.ext4, cfg.ext4, var.ext4) if they exist
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/images/$img" ]; then
cp "$ROOT_DIR/images/$img" "$BINARIES_DIR/"
fi
done
elif [ -f "$ROOT_DIR/rootfs.squashfs" ]; then
# Directory directly containing rootfs.squashfs
echo "Copying rootfs from $ROOT_DIR/rootfs.squashfs to $BINARIES_DIR/"
cp "$ROOT_DIR/rootfs.squashfs" "$BINARIES_DIR/"
# Copy partition images if they exist in same directory
for img in aux.ext4 cfg.ext4 var.ext4; do
if [ -f "$ROOT_DIR/$img" ]; then
cp "$ROOT_DIR/$img" "$BINARIES_DIR/"
fi
done
else
echo "Error: Could not find rootfs.squashfs in $ROOT_DIR" >&2
exit 1
fi
fi
BOARD_DIR=$(dirname "$0") BOARD_DIR=$(dirname "$0")
GENIMAGE_CFG="${BUILD_DIR}/genimage.cfg" GENIMAGE_CFG="${BUILD_DIR}/genimage.cfg"
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp" GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
@@ -9,36 +155,57 @@ GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
# key and our ixboot scripts. Make sure here they are installed in the # key and our ixboot scripts. Make sure here they are installed in the
# proper directory so genimage can create the DOS partition the SPL # proper directory so genimage can create the DOS partition the SPL
# reads config.txt from. # reads config.txt from.
find "${BINARIES_DIR}" -type f -name '*.dtbo' -exec mv '{}' "${BINARIES_DIR}/rpi-firmware/overlays/" \; find "${BINARIES_DIR}" -type f -name '*.dtbo' ! -path "${BINARIES_DIR}/rpi-firmware/overlays/*" -exec \
mv '{}' "${BINARIES_DIR}/rpi-firmware/overlays/" \;
# Create FILES array for the genimage.cfg generation # Create FILES array for the genimage.cfg generation
FILES="" FILES=""
for f in "${BINARIES_DIR}"/rpi-firmware/*; do for f in "${BINARIES_DIR}"/rpi-firmware/*; do
case "$f" in case "$f" in
*~|*.bak) continue ;; *~ | *.bak)
continue
;;
esac esac
echo "${FILES}" | grep -q `basename $f` && continue # If already exist it has been added by us. # If already exist it has been added by us.
echo "${FILES}" | grep -q "$(basename "$f")" && continue
FILES="${FILES}\t\t\t\"${f#"${BINARIES_DIR}/"}\",\n" FILES="${FILES}\t\t\t\"${f#"${BINARIES_DIR}/"}\",\n"
done done
FILES="${FILES}\t\t\t\"splash.bmp\",\n" FILES="${FILES}\t\t\t\"splash.bmp\",\n"
echo $FILES
KERNEL=$(sed -n 's/^kernel=//p' "${BINARIES_DIR}/rpi-firmware/config.txt") KERNEL=$(sed -n 's/^kernel=//p' "${BINARIES_DIR}/rpi-firmware/config.txt")
FILES="${FILES}\t\t\t\"${KERNEL}\"" FILES="${FILES}\t\t\t\"${KERNEL}\""
# Create genimage.cfg from template .in
sed "s|#BOOT_FILES#|${FILES}|" "${BOARD_DIR}/genimage.cfg.in" | \ sed "s|#BOOT_FILES#|${FILES}|" "${BOARD_DIR}/genimage.cfg.in" | \
sed "s|#INFIX_ID#|${INFIX_ID}|" | \ sed "s|#INFIX_ID#|${INFIX_ID}|" | \
sed "s|#VERSION#|${RELEASE}|" > "${GENIMAGE_CFG}" sed "s|#VERSION#|${RELEASE}|" > "${GENIMAGE_CFG}"
# Create temporary root path
ROOTPATH_TMP=$(mktemp -d) ROOTPATH_TMP=$(mktemp -d)
trap 'rm -rf \"$ROOTPATH_TMP\"' EXIT trap 'rm -rf \"$ROOTPATH_TMP\"' EXIT
# Clean previous genimage temp directory
rm -rf "${GENIMAGE_TMP}" rm -rf "${GENIMAGE_TMP}"
# Generate the SD card image
genimage \ genimage \
--rootpath "${ROOTPATH_TMP}" \ --rootpath "${ROOTPATH_TMP}" \
--tmppath "${GENIMAGE_TMP}" \ --tmppath "${GENIMAGE_TMP}" \
--inputpath "${BINARIES_DIR}" \ --inputpath "${BINARIES_DIR}" \
--outputpath "${BINARIES_DIR}" \ --outputpath "${BINARIES_DIR}" \
--config "${GENIMAGE_CFG}" --config "${GENIMAGE_CFG}"
# Print the resulting image path
if [ "$STANDALONE" -eq 1 ]; then
echo ""
echo "SD card image created successfully:"
for img in "${BINARIES_DIR}"/*-sdcard.img; do
if [ -f "$img" ]; then
# Get relative path from current directory
rel_path=$(realpath --relative-to="$PWD" "$img" 2>/dev/null || echo "$img")
echo " $rel_path"
fi
done
fi
+5 -5
View File
@@ -542,10 +542,10 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
err = srx_get_diff(session, &diff); err = srx_get_diff(session, &diff);
if (err) if (err)
goto err_release_data; goto done;
if (!diff) if (!diff)
goto err_release_data; goto done;
/* Create /etc/firewalld+ directory structure */ /* Create /etc/firewalld+ directory structure */
if (fmkpath(0755, FIREWALLD_DIR_NEXT) || if (fmkpath(0755, FIREWALLD_DIR_NEXT) ||
@@ -554,7 +554,7 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
fmkpath(0755, FIREWALLD_POLICIES_DIR)) { fmkpath(0755, FIREWALLD_POLICIES_DIR)) {
ERROR("Failed creating " FIREWALLD_DIR_NEXT " directory structure"); ERROR("Failed creating " FIREWALLD_DIR_NEXT " directory structure");
err = SR_ERR_SYS; err = SR_ERR_SYS;
goto err_release_data; goto done;
} }
if (lydx_get_descendant(diff, "firewall", "default", NULL) || if (lydx_get_descendant(diff, "firewall", "default", NULL) ||
@@ -630,7 +630,7 @@ static int change(sr_session_ctx_t *session, uint32_t sub_id, const char *module
if (generate_policy(cnode, name, &priority)) { if (generate_policy(cnode, name, &priority)) {
ERROR("Failed to generate policy %s", name); ERROR("Failed to generate policy %s", name);
goto err_release_data; goto done;
} }
} }
} }
@@ -644,7 +644,7 @@ done:
if (diff) if (diff)
lyd_free_tree(diff); lyd_free_tree(diff);
err_release_data:
if (cfg) if (cfg)
sr_release_data(cfg); sr_release_data(cfg);
Executable
+74
View File
@@ -0,0 +1,74 @@
#!/bin/sh
# RESTCONF CLI wrapper for curl
# Show usage and exit
usage()
{
cat <<-EOF >&2
Usage: $0 [-h HOST] [-d DATASTORE] [-u USER:PASS] METHOD PATH [CURL_ARGS...]
Options:
-h HOST Target host (default: infix.local)
-d DS Datastore: running, operational, startup (default: running)
-u CREDS Credentials as user:pass (default: admin:admin)
Methods: GET, POST, PUT, PATCH, DELETE
EOF
exit "$1"
}
# Default values
HOST=${HOST:-infix.local}
DATASTORE=running
AUTH=admin:admin
# Parse options
while getopts "h:d:u:" opt; do
case $opt in
h) HOST="$OPTARG" ;;
d) DATASTORE="$OPTARG" ;;
u) AUTH="$OPTARG" ;;
*) usage 1 ;;
esac
done
shift $((OPTIND - 1))
# Validate required arguments
if [ $# -lt 2 ]; then
echo "Error: METHOD and PATH are required" >&2
usage 1
fi
METHOD=$1
PATH=$2
shift 2
# Ensure PATH starts with /
case "$PATH" in
/*) ;;
*) PATH="/$PATH" ;;
esac
# Build URL based on datastore
case "$DATASTORE" in
running|startup)
URL="https://${HOST}/restconf/data${PATH}"
;;
operational)
URL="https://${HOST}/restconf/data${PATH}"
;;
*)
echo "Error: Invalid datastore '$DATASTORE'. Use: running, operational, or startup" >&2
exit 1
;;
esac
# Execute curl with all remaining arguments passed through
exec /usr/bin/curl \
--insecure \
--user "${AUTH}" \
--request "${METHOD}" \
--header "Content-Type: application/yang-data+json" \
--header "Accept: application/yang-data+json" \
"$@" \
"${URL}"