Compare commits

..
Author SHA1 Message Date
Richard Alpe 1f372dffe6 board/common: tune kernel memory settings
Add vm.conf with sysctl parameters optimized for embedded network
devices 512MB-8GB of memory.

Focus on fast recovery and determinism.
- Panic on OOM
- Aggressive dirty page writeback
- Increased watermark scale factor for proactive reclaim

Includes tuning guide documentation for alternative scenarios.

Signed-off-by: Richard Alpe <richard@bit42.se>
2025-12-08 15:54:45 +01:00
477 changed files with 8319 additions and 38246 deletions
+80 -21
View File
@@ -12,6 +12,10 @@ on:
- bananapi-bpi-r3
- friendlyarm-nanopi-r2s
default: 'raspberrypi-rpi64'
use_latest_release:
description: 'Use latest release artifacts instead of workflow artifacts'
type: boolean
default: false
jobs:
create-image:
@@ -50,19 +54,19 @@ jobs:
run: |
case "${{ inputs.board }}" in
raspberrypi-rpi64)
echo "BOOTLOADER=rpi64-boot" >> $GITHUB_ENV
echo "ARCH=aarch64" >> $GITHUB_ENV
echo "BOOTLOADER=rpi64_boot" >> $GITHUB_ENV
echo "TARGET=aarch64" >> $GITHUB_ENV
echo "BUILD_EMMC=false" >> $GITHUB_ENV
;;
bananapi-bpi-r3)
echo "BOOTLOADER_SD=bpi-r3-sd-boot" >> $GITHUB_ENV
echo "BOOTLOADER_EMMC=bpi-r3-emmc-boot" >> $GITHUB_ENV
echo "ARCH=aarch64" >> $GITHUB_ENV
echo "BOOTLOADER_SD=bpi_r3_sd_boot" >> $GITHUB_ENV
echo "BOOTLOADER_EMMC=bpi_r3_emmc_boot" >> $GITHUB_ENV
echo "TARGET=aarch64" >> $GITHUB_ENV
echo "BUILD_EMMC=true" >> $GITHUB_ENV
;;
friendlyarm-nanopi-r2s)
echo "BOOTLOADER=nanopi-r2s-boot" >> $GITHUB_ENV
echo "ARCH=aarch64" >> $GITHUB_ENV
echo "BOOTLOADER=nanopi_r2s_boot" >> $GITHUB_ENV
echo "TARGET=aarch64" >> $GITHUB_ENV
echo "BUILD_EMMC=false" >> $GITHUB_ENV
;;
*)
@@ -70,7 +74,7 @@ jobs:
exit 1
;;
esac
echo "Arch: $ARCH for board: ${{ inputs.board }}"
echo "Target: $TARGET for board: ${{ inputs.board }}"
if [ "$BUILD_EMMC" = "true" ]; then
echo "Building both SD and eMMC images"
echo "SD Bootloader: $BOOTLOADER_SD"
@@ -81,12 +85,16 @@ jobs:
fi
- name: Download bootloader artifacts
if: ${{ !inputs.use_latest_release }}
run: |
# Download bootloader from latest-boot release tag
# Download from latest bootloader build workflow on main branch
gh run list --workflow=build-boot.yml --branch=main --limit=1 --status=success --json databaseId --jq '.[0].databaseId' > latest_boot_run_id
BOOT_RUN_ID=$(cat latest_boot_run_id)
if [ "$BUILD_EMMC" = "true" ]; then
# Download both SD and eMMC bootloaders for boards that support both
echo "Downloading SD bootloader: ${BOOTLOADER_SD}"
gh release download latest-boot --pattern "*${BOOTLOADER_SD}*" --dir temp_bootloader_sd/
gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER_SD} --dir temp_bootloader_sd/
mkdir -p output_sd/images
cd temp_bootloader_sd/
tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/
@@ -94,7 +102,7 @@ jobs:
rm -rf temp_bootloader_sd/
echo "Downloading eMMC bootloader: ${BOOTLOADER_EMMC}"
gh release download latest-boot --pattern "*${BOOTLOADER_EMMC}*" --dir temp_bootloader_emmc/
gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER_EMMC} --dir temp_bootloader_emmc/
mkdir -p output_emmc/images
cd temp_bootloader_emmc/
tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/
@@ -107,7 +115,7 @@ jobs:
ls -la output_emmc/images/
else
# Single bootloader for boards that only support SD
gh release download latest-boot --pattern "*${BOOTLOADER}*" --dir temp_bootloader/
gh run download ${BOOT_RUN_ID} --name artifact-${BOOTLOADER} --dir temp_bootloader/
# Extract bootloader directly to output/images
cd temp_bootloader/
@@ -122,6 +130,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download Infix artifacts
if: ${{ !inputs.use_latest_release }}
run: |
# Download from latest Kernelkit Trigger workflow for main branch
gh run list --workflow=164295764 --branch=main --limit=1 --status=success --json databaseId --jq '.[0].databaseId' > latest_infix_run_id
@@ -129,7 +138,7 @@ jobs:
if [ "$BUILD_EMMC" = "true" ]; then
# Copy Infix artifacts to both SD and eMMC output directories
gh run download ${INFIX_RUN_ID} --name artifact-${ARCH} --dir temp_infix/
gh run download ${INFIX_RUN_ID} --name artifact-${TARGET} --dir temp_infix/
cd temp_infix/
tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/
@@ -143,7 +152,7 @@ jobs:
ls -la output_emmc/images/
else
# Single output directory for SD-only boards
gh run download ${INFIX_RUN_ID} --name artifact-${ARCH} --dir temp_infix/
gh run download ${INFIX_RUN_ID} --name artifact-${TARGET} --dir temp_infix/
# Extract Infix directly to output/images
cd temp_infix/
@@ -157,6 +166,58 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download from latest releases
if: ${{ inputs.use_latest_release }}
run: |
if [ "$BUILD_EMMC" = "true" ]; then
# Download both SD and eMMC bootloaders
gh release download latest-boot --pattern "*${BOOTLOADER_SD}*" --dir temp_bootloader_sd/
mkdir -p output_sd/images
cd temp_bootloader_sd/
tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/
cd ../
rm -rf temp_bootloader_sd/
gh release download latest-boot --pattern "*${BOOTLOADER_EMMC}*" --dir temp_bootloader_emmc/
mkdir -p output_emmc/images
cd temp_bootloader_emmc/
tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/
cd ../
rm -rf temp_bootloader_emmc/
# Download Infix once and extract to both directories
gh release download latest --pattern "*${TARGET}*" --dir temp_infix/
cd temp_infix/
tar -xzf *.tar.gz --strip-components=1 -C ../output_sd/images/
tar -xzf *.tar.gz --strip-components=1 -C ../output_emmc/images/
cd ../
rm -rf temp_infix/
echo "SD files extracted to output_sd/images:"
ls -la output_sd/images/
echo "eMMC files extracted to output_emmc/images:"
ls -la output_emmc/images/
else
# Download latest bootloader release
gh release download latest-boot --pattern "*${BOOTLOADER}*" --dir temp_bootloader/
cd temp_bootloader/
tar -xzf *.tar.gz --strip-components=1 -C ../output/images/
cd ../
rm -rf temp_bootloader/
# Download latest Infix release
gh release download latest --pattern "*${TARGET}*" --dir temp_infix/
cd temp_infix/
tar -xzf *.tar.gz --strip-components=1 -C ../output/images/
cd ../
rm -rf temp_infix/
echo "All files extracted to output/images:"
ls -la output/images/
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Verify extracted files
run: |
if [ "$BUILD_EMMC" = "true" ]; then
@@ -188,7 +249,7 @@ jobs:
export BR2_EXTERNAL_INFIX_PATH=$PWD
export RELEASE=""
export INFIX_ID="infix"
./utils/mkimage.sh -t sdcard ${{ inputs.board }}
./utils/mkimage.sh ${{ inputs.board }}
fi
- name: Create eMMC image
@@ -286,11 +347,10 @@ jobs:
# SD Card & eMMC Image Build Complete! 🚀
**Board:** ${{ inputs.board }}
**Arch:** ${{ env.ARCH }}
**Target:** ${{ env.TARGET }}
**SD Bootloader:** ${{ env.BOOTLOADER_SD }}
**eMMC Bootloader:** ${{ env.BOOTLOADER_EMMC }}
**Bootloader Source:** latest-boot release
**Infix Source:** Latest workflow run on main
**Artifact Source:** ${{ inputs.use_latest_release && 'Latest Release' || 'Latest Workflow Run' }}
## Created Images
$(find output/images/ -name "*.img" -o -name "*.img.bmap" | xargs ls -lh 2>/dev/null | awk '{print "- " $9 " (" $5 ")"}' || echo "- No images found")
@@ -303,10 +363,9 @@ jobs:
# SD Card Image Build Complete! 🚀
**Board:** ${{ inputs.board }}
**Arch:** ${{ env.ARCH }}
**Target:** ${{ env.TARGET }}
**Bootloader:** ${{ env.BOOTLOADER }}
**Bootloader Source:** latest-boot release
**Infix Source:** Latest workflow run on main
**Artifact Source:** ${{ inputs.use_latest_release && 'Latest Release' || 'Latest Workflow Run' }}
## Created Images
$(find output/images/ -name "*.img" -o -name "*.img.bmap" | xargs ls -lh 2>/dev/null | awk '{print "- " $9 " (" $5 ")"}' || echo "- No images found")
+7 -7
View File
@@ -1,4 +1,4 @@
name: Check Kernel 6.18 Release
name: Check Kernel 6.12 Release
on:
schedule:
@@ -17,12 +17,12 @@ jobs:
fetch-depth: 0
token: ${{ secrets.KERNEL_UPDATE_TOKEN }}
- name: Fetch kernel.org and check for 6.18 release
- name: Fetch kernel.org and check for 6.12 release
id: check
run: |
set -e -o pipefail
# Fetch the kernel.org frontpage and extract 6.18 version
CURRENT_VERSION=$(curl -s https://www.kernel.org/ | grep -oP '6\.18\.\d+' | head -n1)
# Fetch the kernel.org frontpage and extract 6.12 version
CURRENT_VERSION=$(curl -s https://www.kernel.org/ | grep -oP '6\.12\.\d+' | head -n1)
if [ -z "$CURRENT_VERSION" ]; then
echo "Failed to fetch kernel version"
@@ -30,7 +30,7 @@ jobs:
fi
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current 6.18 kernel version: $CURRENT_VERSION"
echo "Current 6.12 kernel version: $CURRENT_VERSION"
# Get the version from infix defconfig
INFIX_VERSION=$(grep 'BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE=' configs/aarch64_defconfig | cut -d'"' -f2)
@@ -47,7 +47,7 @@ jobs:
echo "PR already exists for kernel $CURRENT_VERSION, skipping"
else
echo "new_release=true" >> $GITHUB_OUTPUT
echo "🎉 New 6.18 kernel released: $CURRENT_VERSION (infix version: $INFIX_VERSION)"
echo "🎉 New 6.12 kernel released: $CURRENT_VERSION (infix version: $INFIX_VERSION)"
fi
else
echo "new_release=false" >> $GITHUB_OUTPUT
@@ -99,7 +99,7 @@ jobs:
BRANCH_NAME: ${{ steps.branch.outputs.name }}
run: |
set -e -o pipefail
./utils/kernel-upgrade.sh linux 6.18 "$BRANCH_NAME"
./utils/kernel-upgrade.sh linux "$BRANCH_NAME"
- name: Create pull request
if: steps.check.outputs.new_release == 'true'
+5 -1
View File
@@ -104,7 +104,11 @@ jobs:
- name: Extract ChangeLog entry ...
run: |
cat doc/ChangeLog.md | ./utils/extract-changelog.sh > release.md
awk '/^-----*$/{if (x == 1) exit; x=1;next}x' doc/ChangeLog.md \
|head -n -1 > release.md
echo "" >> release.md
echo "> [!TIP]" >> release.md
echo "> **Try Infix in GNS3!** Download the appliance from the [GNS3 Marketplace](https://gns3.com/marketplace/appliances/infix) to test Infix in a virtual network environment without hardware." >> release.md
cat release.md
- uses: ncipollo/release-action@v1
-2
View File
@@ -1,7 +1,6 @@
*~
.claude
.gdb_history
.claude
/.backup
/.ccache
/dl
@@ -11,4 +10,3 @@
/test/.log
/local.mk
/test/spec/Readme.adoc
+28 -25
View File
@@ -16,12 +16,10 @@ if something goes wrong. Deploy once, trust forever.
**🤝 Friendly**
Actually easy to use. Auto-generated CLI from standard YANG models comes
with built-in help for every command — just hit <kbd>?</kbd> or
<kbd>TAB</kbd> for context-aware assistance.
Familiar NETCONF & RESTCONF APIs and [comprehensive documentation][4]
mean you're never stuck. Whether you're learning networking or managing
enterprise infrastructure.
with built-in help for every command — just hit `?` or TAB for
context-aware assistance. Familiar NETCONF/RESTCONF APIs and
[comprehensive documentation][4] mean you're never stuck. Whether
you're learning networking or managing enterprise infrastructure.
**🛡️ Secure**
Built with security as a foundation, not an afterthought. Minimal
@@ -55,24 +53,27 @@ your device, your rules.
Consistent tooling from development to production deployment.
How about a digital twin using raw Qemu or [GNS3](https://gns3.com/infix)!
## Quick Example
## See It In Action
Configure an interface in seconds - the CLI guides you with built-in help:
<pre><code>admin@infix-12-34-56:/> <b>configure</b>
admin@infix-12-34-56:/config/> <b>edit interface eth0</b>
admin@infix-12-34-56:/config/interface/eth0/> <b>set ipv4</b> <kbd>TAB</kbd>
address autoconf bind-ni-name dhcp
enabled forwarding mtu neighbor
admin@infix-12-34-56:/config/interface/eth0/> <b>set ipv4 address 192.168.2.200 prefix-length 24</b>
admin@infix-12-34-56:/config/interface/eth0/> <b>show</b>
<details><summary><b>Click Here for an example CLI Session</b></summary>
```bash
admin@infix-12-34-56:/> configure
admin@infix-12-34-56:/config/> edit interface eth0
admin@infix-12-34-56:/config/interface/eth0/> set ipv4 <TAB>
address autoconf bind-ni-name enabled
forwarding mtu neighbor
admin@infix-12-34-56:/config/interface/eth0/> set ipv4 address 192.168.2.200 prefix-length 24
admin@infix-12-34-56:/config/interface/eth0/> show
type ethernet;
ipv4 {
address 192.168.2.200 {
prefix-length 24;
}
}
admin@infix-12-34-56:/config/interface/eth0/> <b>diff</b>
admin@infix-12-34-56:/config/interface/eth0/> diff
interfaces {
interface eth0 {
+ ipv4 {
@@ -82,23 +83,25 @@ interfaces {
+ }
}
}
admin@infix-12-34-56:/config/interface/eth0/> <b>leave</b>
admin@infix-12-34-56:/> <b>show interfaces</b>
<u>INTERFACE PROTOCOL STATE DATA </u>
admin@infix-12-34-56:/config/interface/eth0/> leave
admin@infix-12-34-56:/> show interfaces
INTERFACE PROTOCOL STATE DATA
eth0 ethernet UP 52:54:00:12:34:56
ipv4 192.168.2.200/24 (static)
ipv6 fe80::5054:ff:fe12:3456/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@infix-12-34-56:/> <b>copy running startup</b>
</code></pre>
admin@infix-12-34-56:/> copy running-config startup-config
```
Notice how <kbd>TAB</kbd> completion shows available options, `show`
displays current config, and `diff` shows exactly what changed before
you commit your changes with the `leave` command.
Notice how TAB completion shows available options, `show` displays
current config, and `diff` shows exactly what changed before you
commit your changes with the `leave` command.
For more information, see [CLI documentation][3].
</details>
> [Full CLI documentation →][3]
## Get Started
@@ -108,7 +111,7 @@ containers for any custom functionality you need.
### Supported Platforms
- **Raspberry Pi 2B/3B/4B/CM4** - Perfect for home labs, learning, and prototyping
- **Raspberry Pi 4B** - Perfect for home labs, learning, and prototyping
- **Banana Pi-R3** - Your next home router and gateway
- **NanoPi R2S** - Compact dual-port router in a tiny package
- **x86_64** - Run in VMs or on mini PCs for development and testing
-18
View File
@@ -1,18 +0,0 @@
Board Support
=============
The board support for an architecture always starts with Qemu support,
this is what each `linux_defconfig` at the very least sets up. Then
each `$BR2_ARCH` has additional BSPs, e.g., Banana Pi BPI-R3.
The `board/` directory is matched with the `configs/*_defconfigs` and
the only execption is `board/common/`, which holds all shared files for
Infix builds.
Each `board/$BR2_ARCH/` can then have vendor/product sub-directories
for the BSPs which may contain "fixups" to the base kernel config and
any additional device tree files that should be included as well.
To rebuild a board-specific package, e.g. NanoPi R2S:
make friendlyarm-nanopi-r2s-rebuild all
+36 -79
View File
@@ -31,11 +31,14 @@ CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_PROFILING=y
CONFIG_KEXEC=y
CONFIG_ARCH_MULTI_V6=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_VIRT=y
CONFIG_ARCH_BCM=y
CONFIG_ARCH_BCM2835=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y
@@ -44,6 +47,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPUFREQ_DT=y
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
CONFIG_AEABI=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_KERNEL_MODE_NEON=y
@@ -74,6 +78,7 @@ CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_IPV6_SIT=m
@@ -89,31 +94,12 @@ CONFIG_BRIDGE_NETFILTER=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_PROCFS=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_AMANDA=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_H323=y
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
CONFIG_NF_CONNTRACK_SNMP=y
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SANE=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NF_CT_NETLINK_TIMEOUT=y
CONFIG_NF_CT_NETLINK_HELPER=y
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=y
CONFIG_NFT_CT=m
CONFIG_NFT_FLOW_OFFLOAD=y
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
@@ -122,22 +108,15 @@ CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
CONFIG_NFT_TUNNEL=m
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=y
CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_FIB_INET=y
CONFIG_NFT_XFRM=m
CONFIG_NFT_SOCKET=m
CONFIG_NFT_OSF=m
CONFIG_NFT_TPROXY=y
CONFIG_NFT_SYNPROXY=y
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NFT_FIB_NETDEV=y
CONFIG_NFT_REJECT_NETDEV=m
CONFIG_NF_FLOW_TABLE_INET=y
CONFIG_NF_FLOW_TABLE=y
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
@@ -154,58 +133,29 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_IP_SET=y
CONFIG_IP_SET_BITMAP_IP=y
CONFIG_IP_SET_BITMAP_IPMAC=y
CONFIG_IP_SET_BITMAP_PORT=y
CONFIG_IP_SET_HASH_IP=y
CONFIG_IP_SET_HASH_IPMARK=y
CONFIG_IP_SET_HASH_IPPORT=y
CONFIG_IP_SET_HASH_IPPORTIP=y
CONFIG_IP_SET_HASH_IPPORTNET=y
CONFIG_IP_SET_HASH_IPMAC=y
CONFIG_IP_SET_HASH_MAC=y
CONFIG_IP_SET_HASH_NETPORTNET=y
CONFIG_IP_SET_HASH_NET=y
CONFIG_IP_SET_HASH_NETNET=y
CONFIG_IP_SET_HASH_NETPORT=y
CONFIG_IP_SET_HASH_NETIFACE=y
CONFIG_IP_SET_LIST_SET=y
CONFIG_NFT_DUP_IPV4=y
CONFIG_NFT_FIB_IPV4=y
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_LOG_ARP=y
CONFIG_NF_LOG_IPV4=y
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NFT_DUP_IPV6=y
CONFIG_NFT_FIB_IPV6=y
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_MATCH_SRH=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
CONFIG_NF_CONNTRACK_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
@@ -244,16 +194,16 @@ CONFIG_NET_MPLS_GSO=y
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
CONFIG_NET_PKTGEN=y
CONFIG_CFG80211=m
CONFIG_MAC80211=m
CONFIG_RFKILL=y
# CONFIG_WIRELESS is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_LWTUNNEL=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_IOV=y
CONFIG_PCI_AARDVARK=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_PCIE_ARMADA_8K=y
CONFIG_UEVENT_HELPER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
@@ -271,6 +221,7 @@ CONFIG_BLK_DEV_NVME=y
CONFIG_SRAM=y
CONFIG_EEPROM_AT24=y
# CONFIG_SCSI_PROC_FS is not set
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SAS_LIBSAS=y
CONFIG_SCSI_SAS_ATA=y
@@ -279,6 +230,7 @@ CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_MOBILE_LPM_POLICY=0
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_MVEBU=y
CONFIG_PATA_OF_PLATFORM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
@@ -306,6 +258,8 @@ CONFIG_SMSC911X=y
CONFIG_USB_LAN78XX=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_BRCMFMAC=m
CONFIG_ZD1211RW=m
CONFIG_INPUT_MOUSEDEV=m
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_TOUCHSCREEN=y
@@ -319,19 +273,22 @@ CONFIG_SERIAL_8250_BCM2835AUX=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_DEV_BUS=y
CONFIG_TTY_PRINTK=y
CONFIG_HVC_DRIVER=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_BCM2835=m
CONFIG_SPI=y
CONFIG_SPI_BCM2835=y
CONFIG_SPI_BCM2835AUX=y
CONFIG_GPIO_SYSFS=y
CONFIG_SENSORS_RASPBERRYPI_HWMON=m
CONFIG_THERMAL=y
CONFIG_BCM2711_THERMAL=y
CONFIG_BCM2835_THERMAL=m
CONFIG_WATCHDOG=y
CONFIG_I6300ESB_WDT=y
CONFIG_BCM2835_WDT=y
CONFIG_I6300ESB_WDT=y
CONFIG_MFD_SYSCON=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -339,12 +296,12 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_DRM=y
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
CONFIG_DRM_SIMPLEDRM=y
CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_TOSHIBA_TC358762=m
CONFIG_DRM_V3D=m
CONFIG_DRM_VC4=m
CONFIG_DRM_VC4_HDMI_CEC=y
CONFIG_DRM_SIMPLEDRM=y
CONFIG_FB=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_SOUND=y
@@ -353,7 +310,6 @@ CONFIG_SND_SOC=y
CONFIG_SND_BCM2835_SOC_I2S=y
CONFIG_HID_GENERIC=m
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_OTG=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC2=y
@@ -387,6 +343,7 @@ CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_STAGING=y
CONFIG_SND_BCM2835=m
CONFIG_VIDEO_BCM2835=m
CONFIG_CLK_RASPBERRYPI=y
CONFIG_MAILBOX=y
CONFIG_BCM2835_MBOX=y
@@ -395,6 +352,8 @@ CONFIG_RASPBERRYPI_POWER=y
CONFIG_PWM=y
CONFIG_PWM_BCM2835=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_FANOTIFY=y
@@ -417,6 +376,8 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_CRYPTO_CCM=y
CONFIG_CRYPTO_GCM=y
# CONFIG_XZ_DEC_ARM is not set
# CONFIG_XZ_DEC_ARMTHUMB is not set
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=32
CONFIG_PRINTK_TIME=y
@@ -426,13 +387,9 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=20
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_WQ_CPU_INTENSIVE_REPORT=y
CONFIG_TEST_LOCKUP=m
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_RCU_TRACE is not set
CONFIG_FUNCTION_TRACER=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_MEMTEST=y
@@ -41,31 +41,14 @@
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{
"id": "netmask"
},
{
"id": "broadcast"
},
{
"id": "router"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "ntp-server"
},
{
"id": "vendor-class",
"value": "Raspberry Pi 2 Model B"
}
{"id": "netmask"},
{"id": "broadcast"},
{"id": "router"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "ntp-server"},
{"id": "vendor-class", "value": "Raspberry Pi 2 Model B"}
]
}
}
@@ -88,9 +71,6 @@
},
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{
@@ -98,14 +78,6 @@
"user-name": [
"admin"
]
},
{
"name": "operator",
"user-name": []
},
{
"name": "guest",
"user-name": []
}
]
},
@@ -125,37 +97,6 @@
}
]
},
{
"name": "operator-acl",
"group": [
"operator"
],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time."
}
]
},
{
"name": "guest-acl",
"group": [
"guest"
],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests cannot change anything or exec rpcs."
}
]
},
{
"name": "default-deny-all",
"group": [
@@ -163,25 +104,11 @@
],
"rule": [
{
"name": "deny-password-access",
"name": "deny-password-read",
"module-name": "ietf-system",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes."
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys."
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store."
"action": "deny"
}
]
}
@@ -195,11 +122,7 @@
"name": "default-ssh",
"ssh": {
"tcp-server-parameters": {
"local-bind": [
{
"local-address": "::"
}
]
"local-address": "::"
},
"ssh-server-parameters": {
"server-identity": {
@@ -245,7 +168,7 @@
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo="
},
"infix-meta:meta": {
"version": "1.7"
"version": "1.6"
},
"infix-services:mdns": {
"enabled": true
@@ -6,7 +6,7 @@ define BANANAPI_BPI_R3_LINUX_CONFIG_FIXUPS
$(call KCONFIG_SET_OPT,CONFIG_I2C_GPIO,y)
$(call KCONFIG_SET_OPT,CONFIG_MTK_THERMAL,m)
$(call KCONFIG_ENABLE_OPT,CONFIG_MTK_UART)
$(call KCONFIG_ENABLE_OPT,CONFIG_MEDIATEK_WATCHDOG)
$(call KCONFIG_ENABLE_OPT,CONFIG_MTK_WATCHDOG)
$(call KCONFIG_ENABLE_OPT,CONFIG_MEDIATEK_GE_PHY)
$(call KCONFIG_ENABLE_OPT,CONFIG_REALTEK_PHY)
$(call KCONFIG_ENABLE_OPT,CONFIG_NET_VENDOR_MEDIATEK)
@@ -17,25 +17,7 @@
"state": {
"admin-state": "unlocked"
}
},
{
"name": "radio0",
"class": "infix-hardware:wifi",
"infix-hardware:wifi-radio": {
"country-code": "DE",
"band": "2.4GHz",
"channel": "auto"
}
},
{
"name": "radio1",
"class": "infix-hardware:wifi",
"infix-hardware:wifi-radio": {
"country-code": "DE",
"band": "5GHz",
"channel": "auto"
}
}
]
},
"ietf-interfaces:interfaces": {
@@ -120,115 +102,54 @@
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{
"id": "ntp-server"
},
{
"id": "broadcast"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "router"
},
{
"id": "netmask"
},
{
"id": "vendor-class",
"value": "Banana Pi BPI-R3"
}
{"id": "ntp-server"},
{"id": "broadcast"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "router"},
{"id": "netmask"},
{"id": "vendor-class", "value": "Banana Pi BPI-R3"}
]
}
},
"ietf-ip:ipv6": {
"infix-dhcpv6-client:dhcp": {
"option": [
{
"id": "ntp-server"
},
{
"id": "client-fqdn"
},
{
"id": "domain-search"
},
{
"id": "dns-server"
}
{"id": "ntp-server"},
{"id": "client-fqdn"},
{"id": "domain-search"},
{"id": "dns-server"}
]
}
}
},
{
"name": "wifi0-ap",
"type": "infix-if-type:wifi",
"infix-interfaces:wifi": {
"radio": "radio0",
"access-point": {
"ssid": "Infix",
"security": {
"secret": "wifi"
}
}
},
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
"name": "wifi0",
"type": "infix-if-type:wifi"
},
{
"name": "wifi1-ap",
"type": "infix-if-type:wifi",
"infix-interfaces:wifi": {
"radio": "radio1",
"access-point": {
"ssid": "Infix5Ghz",
"security": {
"secret": "wifi"
}
}
},
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
"name": "wifi1",
"type": "infix-if-type:wifi"
}
]
},
"ietf-keystore:keystore": {
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "genkey",
"public-key-format": "infix-crypto-types:ssh-public-key-format",
"public-key": "",
"private-key-format": "infix-crypto-types:rsa-private-key-format",
"cleartext-private-key": "",
"certificates": {}
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "genkey",
"public-key-format": "infix-crypto-types:ssh-public-key-format",
"public-key": "",
"private-key-format": "infix-crypto-types:rsa-private-key-format",
"cleartext-private-key": "",
"certificates": {}
}
]
}
]
},
"symmetric-keys": {
"symmetric-key": [
{
"name": "wifi",
"infix-keystore:symmetric-key": "infixinfix",
"infix-keystore:key-format": "infix-crypto-types:wifi-preshared-key-format"
}
]
}
},
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{
@@ -236,14 +157,6 @@
"user-name": [
"admin"
]
},
{
"name": "operator",
"user-name": []
},
{
"name": "guest",
"user-name": []
}
]
},
@@ -263,37 +176,6 @@
}
]
},
{
"name": "operator-acl",
"group": [
"operator"
],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time."
}
]
},
{
"name": "guest-acl",
"group": [
"guest"
],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests cannot change anything or exec rpcs."
}
]
},
{
"name": "default-deny-all",
"group": [
@@ -301,25 +183,11 @@
],
"rule": [
{
"name": "deny-password-access",
"name": "deny-password-read",
"module-name": "ietf-system",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes."
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys."
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store."
"action": "deny"
}
]
}
@@ -333,11 +201,7 @@
"name": "default-ssh",
"ssh": {
"tcp-server-parameters": {
"local-bind": [
{
"local-address": "::"
}
]
"local-address": "::"
},
"ssh-server-parameters": {
"server-identity": {
@@ -429,7 +293,7 @@
"policy": [
{
"name": "lan-to-wan",
"action": "accept",
"action": "accept",
"ingress": [
"lan"
],
@@ -441,7 +305,7 @@
]
},
"infix-meta:meta": {
"version": "1.7"
"version": "1.6"
},
"infix-services:mdns": {
"enabled": true
@@ -477,3 +341,4 @@
}
}
}
@@ -1,11 +0,0 @@
{
"sfp1": {
"comment": "Reports it supports autoneg, but if setting it, dagger crashes",
"broken-autoneg": true
},
"sfp2": {
"comment": "Reports it supports autoneg, but if setting it, dagger crashes",
"broken-autoneg": true
}
}
@@ -4,7 +4,6 @@ config BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S
select SDCARD_AUX
select BR2_PACKAGE_INPUT_EVENT_DAEMON
select BR2_PACKAGE_LINUX_FIRMWARE_RTL_815X
select BR2_PACKAGE_INPUT_EVENT_DAEMON
help
FriendlyElec NanoPi R2S is a compact router board based on
the Rockchip RK3328 SoC with dual Gigabit Ethernet ports.
@@ -4,9 +4,6 @@ define FRIENDLYARM_NANOPI_R2S_LINUX_CONFIG_FIXUPS
$(call KCONFIG_ENABLE_OPT,CONFIG_ROCKCHIP_IOMMU)
$(call KCONFIG_ENABLE_OPT,CONFIG_ROCKCHIP_PM_DOMAINS)
$(call KCONFIG_ENABLE_OPT,CONFIG_ROCKCHIP_IODOMAIN)
# TODO: for some reason this just locks up the device
# so we'll have to rely on the softdog :-(
# $(call KCONFIG_ENABLE_OPT,CONFIG_DW_WATCHDOG)
# PHY drivers
$(call KCONFIG_ENABLE_OPT,CONFIG_PHY_ROCKCHIP_EMMC)
@@ -54,10 +51,6 @@ define FRIENDLYARM_NANOPI_R2S_LINUX_CONFIG_FIXUPS
$(call KCONFIG_SET_OPT,CONFIG_NVMEM_ROCKCHIP_EFUSE,m)
$(call KCONFIG_SET_OPT,CONFIG_NVMEM_ROCKCHIP_OTP,m)
# Input layer
$(call KCONFIG_ENABLE_OPT,CONFIG_INPUT_MISC)
$(call KCONFIG_ENABLE_OPT,CONFIG_INPUT_RK805_PWRKEY)
# Network: STMMAC Ethernet (WAN port - RK3328 GMAC with RTL8211E PHY)
$(call KCONFIG_ENABLE_OPT,CONFIG_NET_VENDOR_STMICRO)
$(call KCONFIG_ENABLE_OPT,CONFIG_STMMAC_ETH)
@@ -61,49 +61,24 @@
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{
"id": "ntp-server"
},
{
"id": "broadcast"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "router"
},
{
"id": "netmask"
},
{
"id": "vendor-class",
"value": "NanoPi R2S"
}
{"id": "ntp-server"},
{"id": "broadcast"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "router"},
{"id": "netmask"},
{"id": "vendor-class", "value": "NanoPi R2S"}
]
}
},
"ietf-ip:ipv6": {
"infix-dhcpv6-client:dhcp": {
"option": [
{
"id": "ntp-server"
},
{
"id": "client-fqdn"
},
{
"id": "domain-search"
},
{
"id": "dns-server"
}
{"id": "ntp-server"},
{"id": "client-fqdn"},
{"id": "domain-search"},
{"id": "dns-server"}
]
}
}
@@ -111,24 +86,21 @@
]
},
"ietf-keystore:keystore": {
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "genkey",
"public-key-format": "infix-crypto-types:ssh-public-key-format",
"public-key": "",
"private-key-format": "infix-crypto-types:rsa-private-key-format",
"cleartext-private-key": "",
"certificates": {}
"asymmetric-keys": {
"asymmetric-key": [
{
"name": "genkey",
"public-key-format": "infix-crypto-types:ssh-public-key-format",
"public-key": "",
"private-key-format": "infix-crypto-types:rsa-private-key-format",
"cleartext-private-key": "",
"certificates": {}
}
]
}
]
}
},
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{
@@ -136,14 +108,6 @@
"user-name": [
"admin"
]
},
{
"name": "operator",
"user-name": []
},
{
"name": "guest",
"user-name": []
}
]
},
@@ -163,37 +127,6 @@
}
]
},
{
"name": "operator-acl",
"group": [
"operator"
],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time."
}
]
},
{
"name": "guest-acl",
"group": [
"guest"
],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests cannot change anything or exec rpcs."
}
]
},
{
"name": "default-deny-all",
"group": [
@@ -201,25 +134,11 @@
],
"rule": [
{
"name": "deny-password-access",
"name": "deny-password-read",
"module-name": "ietf-system",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes."
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys."
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store."
"action": "deny"
}
]
}
@@ -233,11 +152,7 @@
"name": "default-ssh",
"ssh": {
"tcp-server-parameters": {
"local-bind": [
{
"local-address": "::"
}
]
"local-address": "::"
},
"ssh-server-parameters": {
"server-identity": {
@@ -329,7 +244,7 @@
"policy": [
{
"name": "lan-to-wan",
"action": "accept",
"action": "accept",
"ingress": [
"lan"
],
@@ -341,7 +256,7 @@
]
},
"infix-meta:meta": {
"version": "1.7"
"version": "1.6"
},
"infix-services:mdns": {
"enabled": true
@@ -20,7 +20,6 @@ cleanup()
{
rm -f "$LED_FILE"
rm -f "$PID_FILE"
kill %% 2>/dev/null
exit 0
}
@@ -32,13 +31,11 @@ remaining_time=$((1800 - $(awk '{print int($1)}' /proc/uptime)))
while [ "$remaining_time" -gt 0 ]; do
check_wan
sleep 1 &
wait $!
sleep 1
remaining_time=$((remaining_time - 1))
done
while :; do
check_wan
sleep 5 &
wait $!
sleep 5
done
+20 -84
View File
@@ -39,6 +39,7 @@ CONFIG_ARM64_ERRATUM_1286807=y
CONFIG_ARM64_ERRATUM_1542419=y
CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_VA_BITS_48=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=64
CONFIG_COMPAT=y
# CONFIG_SUSPEND is not set
@@ -51,6 +52,7 @@ CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
CONFIG_ARM_ARMADA_8K_CPUFREQ=y
CONFIG_ACPI=y
CONFIG_KPROBES=y
CONFIG_JUMP_LABEL=y
# CONFIG_GCC_PLUGINS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -77,6 +79,7 @@ CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_IPV6_SIT=m
@@ -92,31 +95,12 @@ CONFIG_BRIDGE_NETFILTER=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_PROCFS=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_AMANDA=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_H323=y
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
CONFIG_NF_CONNTRACK_SNMP=y
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SANE=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NF_CT_NETLINK_TIMEOUT=y
CONFIG_NF_CT_NETLINK_HELPER=y
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=y
CONFIG_NFT_CT=m
CONFIG_NFT_FLOW_OFFLOAD=y
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
@@ -125,23 +109,15 @@ CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
CONFIG_NFT_TUNNEL=m
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=y
CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_FIB_INET=y
CONFIG_NFT_XFRM=m
CONFIG_NFT_SOCKET=m
CONFIG_NFT_OSF=m
CONFIG_NFT_TPROXY=y
CONFIG_NFT_SYNPROXY=y
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NFT_FIB_NETDEV=y
CONFIG_NFT_REJECT_NETDEV=m
CONFIG_NF_FLOW_TABLE_INET=y
CONFIG_NF_FLOW_TABLE=y
CONFIG_NETFILTER_XTABLES_LEGACY=y
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
@@ -158,69 +134,29 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_IP_SET=y
CONFIG_IP_SET_BITMAP_IP=y
CONFIG_IP_SET_BITMAP_IPMAC=y
CONFIG_IP_SET_BITMAP_PORT=y
CONFIG_IP_SET_HASH_IP=y
CONFIG_IP_SET_HASH_IPMARK=y
CONFIG_IP_SET_HASH_IPPORT=y
CONFIG_IP_SET_HASH_IPPORTIP=y
CONFIG_IP_SET_HASH_IPPORTNET=y
CONFIG_IP_SET_HASH_IPMAC=y
CONFIG_IP_SET_HASH_MAC=y
CONFIG_IP_SET_HASH_NETPORTNET=y
CONFIG_IP_SET_HASH_NET=y
CONFIG_IP_SET_HASH_NETNET=y
CONFIG_IP_SET_HASH_NETPORT=y
CONFIG_IP_SET_HASH_NETIFACE=y
CONFIG_IP_SET_LIST_SET=y
CONFIG_NFT_DUP_IPV4=y
CONFIG_NFT_FIB_IPV4=y
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_LOG_ARP=y
CONFIG_NF_LOG_IPV4=y
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NFT_DUP_IPV6=y
CONFIG_NFT_FIB_IPV6=y
CONFIG_IP_NF_MANGLE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_MATCH_SRH=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
CONFIG_NF_CONNTRACK_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
@@ -308,7 +244,6 @@ CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_NETDEVICES=y
CONFIG_BONDING=m
CONFIG_DUMMY=m
CONFIG_WIREGUARD=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
CONFIG_IPVLAN=m
@@ -472,10 +407,10 @@ CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_SYSFS=y
CONFIG_SOFT_WATCHDOG=y
CONFIG_GPIO_WATCHDOG=y
CONFIG_ARM_SBSA_WATCHDOG=y
CONFIG_ARMADA_37XX_WATCHDOG=y
CONFIG_I6300ESB_WDT=y
CONFIG_MFD_MAX77620=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_ROHM_BD718XX=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -484,6 +419,7 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_PCA9450=y
CONFIG_REGULATOR_QCOM_SPMI=y
CONFIG_REGULATOR_S2MPS11=y
# CONFIG_HID_GENERIC is not set
# CONFIG_HID_A4TECH is not set
# CONFIG_HID_APPLE is not set
@@ -493,11 +429,11 @@ CONFIG_REGULATOR_QCOM_SPMI=y
# CONFIG_HID_CYPRESS is not set
# CONFIG_HID_EZKEY is not set
# CONFIG_HID_KENSINGTON is not set
# CONFIG_HID_LOGITECH is not set
# CONFIG_HID_MICROSOFT is not set
# CONFIG_HID_MONTEREY is not set
CONFIG_USB_ULPI_BUS=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=m
CONFIG_USB_XHCI_MVEBU=m
@@ -515,6 +451,7 @@ CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_ISP1760=y
CONFIG_USB_HSIC_USB3503=m
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_ULPI=y
CONFIG_USB_GADGET=y
CONFIG_USB_SNP_UDC_PLAT=y
@@ -548,6 +485,7 @@ CONFIG_LEDS_TRIGGER_NETDEV=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_PCF8523=y
CONFIG_RTC_DRV_S5M=y
CONFIG_RTC_DRV_DS3232=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_PL031=y
@@ -562,6 +500,7 @@ CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
# CONFIG_SURFACE_PLATFORMS is not set
CONFIG_COMMON_CLK_CS2000_CP=y
CONFIG_COMMON_CLK_S2MPS11=y
CONFIG_COMMON_CLK_XGENE=y
CONFIG_COMMON_CLK_BD718XX=y
CONFIG_MAILBOX=y
@@ -578,7 +517,7 @@ CONFIG_PHY_SAMSUNG_USB2=y
CONFIG_NVMEM_LAYOUT_ONIE_TLV=y
CONFIG_MUX_MMIO=y
CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
@@ -605,6 +544,8 @@ CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_CRYPTO_GHASH_ARM64_CE=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=0
@@ -616,13 +557,8 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=20
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_WQ_CPU_INTENSIVE_REPORT=y
CONFIG_TEST_LOCKUP=m
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_RCU_TRACE is not set
CONFIG_FUNCTION_TRACER=y
# CONFIG_STRICT_DEVMEM is not set
+1 -1
View File
@@ -108,7 +108,7 @@ To configure WiFi as a client, first store your WiFi password in the keystore:
admin@infix:/> configure
admin@infix:/config/> edit keystore symmetric-key mywifi
admin@infix:/config/keystore/…/mywifi/> set key-format wifi-preshared-key-format
admin@infix:/config/keystore/…/mywifi/> set symmetric-key YourWiFiPassword
admin@infix:/config/keystore/…/mywifi/> set cleartext-key YourWiFiPassword
admin@infix:/config/keystore/…/mywifi/> leave
```
@@ -1,4 +0,0 @@
#!/bin/sh
# Workaround for: https://github.com/kernelkit/infix/issues/1357
udevadm control --reload-rules
udevadm trigger --subsystem-match=net --action=add
@@ -10,13 +10,6 @@
"state": {
"admin-state": "unlocked"
}
},
{
"name": "radio0",
"class": "infix-hardware:wifi",
"infix-hardware:wifi-radio": {
"country-code": "00"
}
}
]
},
@@ -45,45 +38,24 @@
{
"name": "eth0",
"type": "infix-if-type:ethernet",
"ietf-ip:ipv6": {},
"ietf-ip:ipv4": {
"infix-dhcp-client:dhcp": {
"option": [
{
"id": "netmask"
},
{
"id": "broadcast"
},
{
"id": "router"
},
{
"id": "domain"
},
{
"id": "hostname"
},
{
"id": "dns-server"
},
{
"id": "ntp-server"
},
{
"id": "vendor-class",
"value": "Raspberry Pi 4 Model B"
}
{"id": "netmask"},
{"id": "broadcast"},
{"id": "router"},
{"id": "domain"},
{"id": "hostname"},
{"id": "dns-server"},
{"id": "ntp-server"},
{"id": "vendor-class", "value": "Raspberry Pi 4 Model B"}
]
}
}
},
{
"name": "wifi0",
"type": "infix-if-type:wifi",
"infix-interfaces:wifi": {
"radio": "radio0"
}
"type": "infix-if-type:wifi"
}
]
},
@@ -103,9 +75,6 @@
},
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{
@@ -113,14 +82,6 @@
"user-name": [
"admin"
]
},
{
"name": "operator",
"user-name": []
},
{
"name": "guest",
"user-name": []
}
]
},
@@ -140,37 +101,6 @@
}
]
},
{
"name": "operator-acl",
"group": [
"operator"
],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time."
}
]
},
{
"name": "guest-acl",
"group": [
"guest"
],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests cannot change anything or exec rpcs."
}
]
},
{
"name": "default-deny-all",
"group": [
@@ -178,25 +108,11 @@
],
"rule": [
{
"name": "deny-password-access",
"name": "deny-password-read",
"module-name": "ietf-system",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes."
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys."
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store."
"action": "deny"
}
]
}
@@ -210,11 +126,7 @@
"name": "default-ssh",
"ssh": {
"tcp-server-parameters": {
"local-bind": [
{
"local-address": "::"
}
]
"local-address": "::"
},
"ssh-server-parameters": {
"server-identity": {
@@ -260,7 +172,7 @@
"infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo="
},
"infix-meta:meta": {
"version": "1.7"
"version": "1.6"
},
"infix-services:mdns": {
"enabled": true
@@ -1,4 +0,0 @@
#!/bin/sh
# Workaround for: https://github.com/kernelkit/infix/issues/1357
udevadm control --reload-rules
udevadm trigger --subsystem-match=net --action=add
@@ -12,15 +12,6 @@
boot_targets = "mmc0";
ethprime = "eth0";
/* Memory layout for kernel boot:
* 0x00200000: Kernel relocation address
* 0x04000000: FDT (64MB, gives enough space for kernels up to ~60MB)
* 0x10000000: Ramdisk (Memsize - 256MB)
*/
kernel_addr_r = "0x00200000";
fdt_addr_r = "0x04000000";
ramdisk_addr_r = "0x10000000";
stdout = "serial";
stderr = "serial";
stdin = "serial";
@@ -1,26 +0,0 @@
#!/bin/sh
set -e
ecc_stat()
{
local chan=
local base=
for chan in 0 1; do
base=$((0xf0020360 + 0x200 * chan))
echo "DRAM Channel $chan ECC Status"
echo -n " Log config: "; devmem $((base + 0x0)) 32
echo -n " 1b errors: "; devmem $((base + 0x4)) 32
echo -n " Info 0: "; devmem $((base + 0x8)) 32
echo -n " Info 1: "; devmem $((base + 0xc)) 32
echo
done
}
[ -n "$1" ] || { echo "usage: $0 OUT-DIR"; exit 1; }
work="$1"/marvell-cn913x
mkdir -p "${work}"
ecc_stat >"${work}"/ecc-stat
@@ -59,9 +59,3 @@
XSWP(a, "e13", 13, &sfp0);
};
};
&cp0_spi1 {
spi-flash@0 {
broken-flash-reset;
};
};
+6 -1
View File
@@ -1016,7 +1016,12 @@ CONFIG_UDHCPC=y
CONFIG_FEATURE_UDHCPC_ARPING=y
CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y
CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
# CONFIG_UDHCPC6 is not set
CONFIG_UDHCPC6_DEFAULT_SCRIPT="/usr/share/udhcpc/default6.script"
CONFIG_UDHCPC6=y
CONFIG_FEATURE_UDHCPC6_RFC3646=y
CONFIG_FEATURE_UDHCPC6_RFC4704=y
CONFIG_FEATURE_UDHCPC6_RFC4833=y
CONFIG_FEATURE_UDHCPC6_RFC5970=y
#
# Common options for DHCP applets
+3 -3
View File
@@ -34,7 +34,7 @@ Depending on how your Linux installation is set up, the following may
require being run with superuser privileges, i.e., you may need to
repend the command with 'sudo'.
$ ./qemu/run.sh
$ ./qemu.sh
You should now see the Infix init system booting up. When the final
"Please press Enter to activate this console." is shown, press Enter
@@ -75,13 +75,13 @@ interface, which requires the following extra package:
We can now enter the configuration:
$ ./qemu/run.sh -c
$ ./qemu.sh -c
Go down to *Networking*, select *TAP*, now you can change the *Number of
TAPs*, e.g. to 10. Exit and save the configuration, then you can start
Qemu again:
$ ./qemu/run.sh
./qemu.sh
> Make sure to do a factory reset from the CLI, otherwise you will be
> stuck with that single interface from before.
+3 -8
View File
@@ -10,18 +10,15 @@
#
# and then call this script with:
#
# ./run.sh -c
# ./qemu.sh -c
#
# To bring up a menuconfig dialog. Select `Exit` and save the changes.
# For more help, see:_
#
# ./run.sh -h
# ./qemu.sh -h
#
# shellcheck disable=SC3037
# Add /sbin to PATH for mkfs.ext4 and such (not default in debian)
export PATH="/sbin:/usr/sbin:$PATH"
qdir=$(dirname "$(readlink -f "$0")")
imgdir=$(readlink -f "${qdir}/..")
prognm=$(basename "$0")
@@ -43,7 +40,7 @@ usage()
echo " Also, qemu.cfg has QEMU_APPEND which can affect this."
echo
echo "Example:"
echo " $prognm -- finit.debug"
echo " qemu.sh -- finit.debug"
echo "___________________________________________________________________"
echo "Note: 'kconfig-frontends' package (Debian/Ubuntu) must be installed"
echo " for -c to work: sudo apt install kconfig-frontents"
@@ -177,8 +174,6 @@ rw_args()
{
[ "$CONFIG_QEMU_RW" ] || return
command -v mkfs.ext4 >/dev/null || die "$prognm: cannot find mkfs.ext4"
if ! [ -f "aux.ext4" ]; then
dd if=/dev/zero of="aux.ext4" bs=1M count=1 >/dev/null 2>&1
mkfs.ext4 -L aux "aux.ext4" >/dev/null 2>&1
+2 -3
View File
@@ -40,12 +40,11 @@ log()
less +G -r "$fn"
}
follow ()
follow()
{
local fn="/var/log/syslog"
[ -n "$1" ] && fn="/var/log/$1"
tail -F -n +1 "$fn"
less +F -r "$fn"
}
_logfile_completions()
+1 -1
View File
@@ -1,2 +1,2 @@
# --log-level debug
ZEBRA_ARGS="-A 127.0.0.1 -u frr -g frr --log syslog --log-level err"
ZEBRA_ARGS="-A 127.0.0.1 -u frr -g frr --log syslog "
@@ -5,5 +5,4 @@
# 'podman load', must not have a timeout.
sysv log:prio:local1,tag:%i kill:30 pid:!/run/container:%i.pid \
pre:0,/usr/sbin/container cleanup:0,/usr/sbin/container \
cgroup.system,delegate \
[2345] <!> :%i container -n %i -- container %i
@@ -1,3 +0,0 @@
service <!> name:hostapd :%i \
[2345] hostapd -P/var/run/hostapd-%i.pid /etc/hostapd-%i.conf \
-- Wi-Fi Access Point @%i
@@ -1,3 +1,3 @@
service name:rousette notify:none log:null <pid/confd> env:/etc/default/confd \
service name:rousette notify:none log <pid/confd> env:/etc/default/confd \
[12345] rousette --syslog -t $CONFD_TIMEOUT \
-- RESTCONF server
@@ -1,3 +1,5 @@
service name:wpa_supplicant :%i \
[2345] wpa_supplicant -s -i %i -c /etc/wpa_supplicant-%i.conf -P/var/run/wpa_supplicant-%i.pid \
-- Wi-Fi Station @%i
[2345] wpa_supplicant -s -i %i -c /etc/wpa_supplicant-%i.conf -P/var/run/wpa_supplicant-%i.pid \
-- WPA supplicant @%i
task name:wifi-scanner :%i [2345] <pid/wpa_supplicant:%i> /usr/libexec/infix/wifi-scanner %i -- Start scanning for SSID @ %i
+15 -7
View File
@@ -1,15 +1,23 @@
# Virtual filesystems
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
tmpfs /media tmpfs mode=1755,nosuid,nodev 0 0
debugfs /sys/kernel/debug debugfs nofail 0 0
cfgfs /config configfs nofail,noauto 0 0
devtmpfs /dev devtmpfs defaults 0 0
mkdir#-p /dev/pts helper none 0 0
devpts /dev/pts devpts mode=620,ptmxmode=0666 0 0
mkdir#-p /dev/shm helper none 0 0
tmpfs /dev/shm tmpfs mode=0777 0 0
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs mode=1777,nosuid,nodev 0 0
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
tmpfs /media tmpfs mode=1755,nosuid,nodev 0 0
sysfs /sys sysfs defaults 0 0
debugfs /sys/kernel/debug debugfs nofail 0 0
cfgfs /config configfs nofail,noauto 0 0
# The chosen backing storage for the overlays placed on /cfg, /etc,
# /home, /root, and /var, are determined dynamically by /usr/libexec/infix/mnt
# depending on the available devices.
mnttmp /mnt/tmp tmpfs defaults 0 0
LABEL=aux /mnt/aux auto noatime,nodiratime,noauto 0 0
LABEL=var /mnt/var ext4 noatime,nodiratime,noauto 0 0
LABEL=cfg /mnt/cfg ext4 noatime,nodiratime,noauto 0 0
LABEL=aux /mnt/aux auto noatime,nodiratime,noauto,errors=remount-ro 0 0
LABEL=var /mnt/var ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
LABEL=cfg /mnt/cfg ext4 noatime,nodiratime,noauto,commit=30,errors=remount-ro 0 0
hostfs /mnt/host 9p cache=none,msize=16384,noauto 0 0
/usr/libexec/infix/mnt# /cfg helper none 0 0
+2 -10
View File
@@ -19,14 +19,6 @@ http {
include /etc/nginx/enabled/*.conf;
# Skip 2xx and 3xx
# Skip 400 (e.g., rrousette syntax errors)
map $status $loggable {
~^[23] 0;
400 0;
default 1;
}
access_log syslog:server=unix:/dev/log,nohostname,facility=local7,severity=warn combined if=$loggable;
error_log syslog:server=unix:/dev/log,nohostname,facility=local7 warn;
access_log syslog:server=unix:/dev/log,nohostname,facility=local7,severity=info;
error_log syslog:server=unix:/dev/log,nohostname,facility=local7 info;
}
@@ -4,14 +4,14 @@ alias ll='ls -alF'
alias ls='ls --color=auto'
export LANG=C.UTF-8
export EDITOR=/usr/bin/editor
export VISUAL=/usr/bin/editor
export EDITOR=/usr/bin/edit
export VISUAL=/usr/bin/edit
export LESS="-P %f (press h for help or q to quit)"
export LESSOPEN="|/usr/bin/lesspipe.sh %s"
alias vim='vi'
alias view='vi -R'
alias emacs='mg'
alias sensible-editor=editor
alias sensible-editor=edit
alias sensible-pager=pager
alias hd="hexdump -C"
+23
View File
@@ -0,0 +1,23 @@
# Memory and OOM tuning for embedded network devices
# Optimized for systems with 512MB-4GB RAM
# Target: Fast and deterministic OOM behavior
# OOM Behavior
# Panic on OOM for fast system reset and recovery
vm.panic_on_oom=1
# Dirty Page Writeback
# Limit dirty pages to 10% of RAM before blocking writers
# Start background writeback at 5% to prevent accumulation
vm.dirty_ratio=10
vm.dirty_background_ratio=5
# Writeback Timing
# Expire dirty pages after 10 seconds (1000 centiseconds)
# Ensures quick flushing on limited-memory systems
vm.dirty_expire_centisecs=1000
# Memory Watermarks
# Increase distance between low/high watermarks for earlier reclaim
# Maintains larger free memory buffer proactively (default: 10)
vm.watermark_scale_factor=150
@@ -1,3 +0,0 @@
# Rename WiFi PHY devices from phy0 to radio0 to avoid name clashes
SUBSYSTEM=="ieee80211", ACTION=="add", KERNEL=="phy*", \
RUN+="/bin/sh -c '/usr/sbin/iw phy %k set name radio%n'"
@@ -1,7 +0,0 @@
# Remove kernel-created WiFi interfaces
# All WiFi interfaces are now virtual interfaces created by confd
SUBSYSTEM=="net", ACTION=="add", KERNEL=="wlan*", \
TEST=="/sys/class/net/$name/phy80211/name", \
PROGRAM="/bin/cat /sys/class/net/%k/phy80211/name", \
TEST!="/run/wifi-cleaned-%c", \
RUN+="/bin/sh -c '/usr/sbin/iw dev %k del && touch /run/wifi-cleaned-%c'"
@@ -0,0 +1 @@
SUBSYSTEM=="net", ACTION=="add", TEST=="/sys/class/net/$name/wireless", NAME="wifi%n"
+22 -31
View File
@@ -90,9 +90,9 @@ reset-reason {
# Monitors file descriptor leaks based on /proc/sys/fs/file-nr
filenr {
enabled = true
interval = 3600
logmark = true
# enabled = true
interval = 300
logmark = false
warning = 0.9
critical = 1.0
# script = "/path/to/alt-reboot-action.sh"
@@ -102,42 +102,33 @@ filenr {
# The script is called with fsmon as the first argument and there
# are two environment variables FSMON_NAME, for the monitored path,
# and FSMON_TYPE indicating either 'blocks' or 'inodes'.
fsmon /var {
enabled = true
interval = 3600
logmark = true
warning = 0.95
critical = 1.0
# script = "/path/to/alt-reboot-action.sh"
}
fsmon /tmp {
enabled = true
interval = 3600
logmark = true
warning = 0.95
critical = 1.0
# script = "/path/to/alt-reboot-action.sh"
}
# Monitors load average based on sysinfo() from /proc/loadavg
# The level is composed from the average of the 1 and 5 min marks.
#loadavg {
#fsmon /var {
# enabled = true
# interval = 300
# logmark = true
# warning = 1.0
# critical = 2.0
# logmark = false
# warning = 0.95
# critical = 1.0
# script = "/path/to/alt-reboot-action.sh"
#}
# Monitors load average based on sysinfo() from /proc/loadavg
# The level is composed from the average of the 1 and 5 min marks.
loadavg {
# enabled = true
interval = 300
logmark = false
warning = 1.0
critical = 2.0
# script = "/path/to/alt-reboot-action.sh"
}
# Monitors free RAM based on data from /proc/meminfo
meminfo {
enabled = true
interval = 3600
logmark = true
# enabled = true
interval = 300
logmark = false
warning = 0.9
critical = 0.97
critical = 0.95
# script = "/path/to/alt-reboot-action.sh"
}
+58
View File
@@ -0,0 +1,58 @@
#!/bin/sh
# User-friendly wrapper for sysrepocfg
# TODO: add import/export, copy, ...
# Edit YANG binary types using sysrepo, base64, and duct tape.
edit()
{
xpath=$1
if [ -z "$xpath" ]; then
echo "Usage: cfg edit \"/full/xpath/to/binary/leaf\""
exit 1
fi
if tmp=$(sysrepocfg -G "$xpath"); then
file=$(mktemp)
echo "$tmp" | base64 -d > "$file"
if /usr/bin/editor "$file"; then
tmp=$(base64 -w0 < "$file")
sysrepocfg -S "$xpath" -u "$tmp"
fi
rm -f "$file"
else
echo "Failed to retrieve value for $xpath"
exit 1
fi
}
usage()
{
echo "Usage:"
echo " cfg CMD [ARG]"
echo
echo "Command:"
echo " edit XPATH Edit YANG binary type"
echo " help This help text"
echo
echo "As a backwards compatible fallback, this script forwards"
echo "all other commands as options to sysrepocfg."
echo
exit 0
}
cmd=$1; shift
case $cmd in
edit)
edit "$1"
;;
help)
usage
;;
*)
set -- "$cmd" "$@"
exec sysrepocfg -f json "$@"
;;
esac
+1
View File
@@ -0,0 +1 @@
/etc/alternatives/editor
+8 -8
View File
@@ -91,7 +91,7 @@ EOF
is_dhcp_running()
{
copy operational -x /infix-dhcp-server:dhcp-server | jq -r '
sysrepocfg -X -f json -m infix-dhcp-server | jq -r '
."infix-dhcp-server:dhcp-server".enabled as $global |
if ."infix-dhcp-server:dhcp-server".subnet? then
(."infix-dhcp-server:dhcp-server".subnet[] |
@@ -110,15 +110,15 @@ dhcp()
case $1 in
detail)
copy operational -x /infix-dhcp-server:dhcp-server | \
sysrepocfg -f json -X -d operational -m infix-dhcp-server | \
jq -C .
;;
stat*)
copy operational -x /infix-dhcp-server:dhcp-server | \
sysrepocfg -f json -X -d operational -m infix-dhcp-server | \
/usr/libexec/statd/cli-pretty "show-dhcp-server" -s
;;
*)
copy operational -x /infix-dhcp-server:dhcp-server | \
sysrepocfg -f json -X -d operational -m infix-dhcp-server | \
/usr/libexec/statd/cli-pretty "show-dhcp-server"
;;
esac
@@ -182,13 +182,13 @@ ifaces()
else
if [ $# -gt 0 ]; then
for iface in $*; do
copy operational -x \
sysrepocfg -f json -X -d operational -x \
"/ietf-interfaces:interfaces/interface[name='$iface']" | \
/usr/libexec/statd/cli-pretty "show-interfaces" -n "$iface"
done
return
fi
copy operational -x /ietf-interfaces:interfaces | \
sysrepocfg -f json -X -d operational -m ietf-interfaces | \
/usr/libexec/statd/cli-pretty "show-interfaces"
fi
}
@@ -227,7 +227,7 @@ rstp()
stp()
{
copy operational -x /ietf-interfaces:interfaces | \
sysrepocfg -f json -X -d operational -m ietf-interfaces | \
/usr/libexec/statd/cli-pretty "show-bridge-stp"
}
@@ -248,7 +248,7 @@ routes()
else
arg="-i ipv4"
fi
copy operational -x /ietf-routing:routing/ribs | \
sysrepocfg -f json -X -d operational -x "/ietf-routing:routing/ribs" | \
/usr/libexec/statd/cli-pretty "show-routing-table" $arg
}
-600
View File
@@ -1,600 +0,0 @@
#!/usr/bin/env python3
"""
iw command wrapper that returns structured JSON data
Usage:
iw.py list - List all PHY devices
iw.py dev - List all interfaces grouped by PHY
iw.py info <device> - Get PHY or interface information
iw.py survey <interface> - Get channel survey data
"""
import sys
import json
import subprocess
import re
def decode_iw_ssid(ssid):
"""Decode iw escaped SSID (\\xHH) to UTF-8, stripping non-printable chars."""
try:
ssid = ssid.encode().decode('unicode_escape').encode('latin-1').decode('utf-8')
except (UnicodeDecodeError, UnicodeEncodeError):
return ssid
return ''.join(c for c in ssid if c.isprintable())
def run_iw(*args):
"""Run iw command and return output"""
try:
result = subprocess.run(
['iw'] + list(args),
capture_output=True,
text=True,
timeout=5
)
if result.returncode == 0:
return result.stdout
return None
except Exception:
return None
def normalize_phy_name(name):
"""
Convert radioN to phyN or vice versa based on what exists in sysfs.
Returns the actual phy name that exists.
"""
import os
# Try the name as-is first
if os.path.exists(f'/sys/class/ieee80211/{name}'):
return name
# Try converting radioN <-> phyN
if name.startswith('radio'):
phy_name = 'phy' + name[5:]
if os.path.exists(f'/sys/class/ieee80211/{phy_name}'):
return phy_name
elif name.startswith('phy'):
radio_name = 'radio' + name[3:]
if os.path.exists(f'/sys/class/ieee80211/{radio_name}'):
return radio_name
# Return original if nothing found
return name
def parse_phy_info(phy_name):
"""
Parse 'iw phy <name> info' output or 'iw <name> info' output
Returns: {bands, driver, manufacturer, max_txpower, num_virtual_interfaces, interface_combinations}
"""
# Normalize the phy name
actual_phy = normalize_phy_name(phy_name)
# Try 'iw phy <name> info' first
output = run_iw('phy', actual_phy, 'info')
# If that fails, try 'iw <name> info' (some systems support this)
if not output:
output = run_iw(actual_phy, 'info')
if not output:
return {}
result = {
'name': phy_name,
'bands': [],
'driver': None,
'manufacturer': None,
'max_txpower': None,
'num_virtual_interfaces': 0,
'interface_combinations': []
}
current_band = None
band_num = 0
in_combinations = False
max_power = None
for line in output.splitlines():
stripped = line.strip()
# Detect band sections
if stripped.startswith('Band '):
if current_band and current_band.get('frequencies'):
result['bands'].append(current_band)
band_num += 1
current_band = {
'band': band_num,
'frequencies': [],
'name': None,
'ht_capable': False,
'vht_capable': False,
'he_capable': False
}
in_combinations = False
# Parse frequencies (handle both "2412 MHz" and "2412.0 MHz" formats)
elif current_band and not in_combinations:
freq_match = re.match(r'\* ([0-9.]+) MHz.*?\(([0-9.]+) dBm\)', stripped)
if freq_match:
freq = int(float(freq_match.group(1))) # Convert "2412.0" to 2412
power = float(freq_match.group(2))
current_band['frequencies'].append(freq)
# Track max power
if max_power is None or power > max_power:
max_power = power
# Check capabilities
if 'HT ' in stripped or 'High Throughput' in stripped:
current_band['ht_capable'] = True
if 'VHT' in stripped or 'Very High Throughput' in stripped:
current_band['vht_capable'] = True
if 'HE ' in stripped or 'High Efficiency' in stripped:
current_band['he_capable'] = True
# Detect interface combinations section
if 'valid interface combinations:' in stripped.lower():
in_combinations = True
continue
# Parse interface combinations
if in_combinations:
if stripped.startswith('*'):
# Parse combination line
comb_info = {'limits': []}
# Parse limits: #{ type } <= max
limit_matches = re.findall(r'#\{\s*([^}]+)\s*\}\s*<=\s*(\d+)', stripped)
for types_str, max_val in limit_matches:
types = [t.strip() for t in types_str.split(',')]
comb_info['limits'].append({
'max': int(max_val),
'types': types
})
# Parse total
total_match = re.search(r'total\s*<=\s*(\d+)', stripped)
if total_match:
comb_info['max_total'] = int(total_match.group(1))
# Parse channels
channels_match = re.search(r'#channels\s*<=\s*(\d+)', stripped)
if channels_match:
comb_info['num_channels'] = int(channels_match.group(1))
if comb_info.get('limits') or comb_info.get('max_total'):
result['interface_combinations'].append(comb_info)
elif not stripped.startswith('#') and ':' in stripped and not stripped.startswith('*'):
# End of combinations section
in_combinations = False
# Add last band
if current_band and current_band.get('frequencies'):
result['bands'].append(current_band)
# Determine band names and assign band numbers
for band in result['bands']:
if band['frequencies']:
freq = band['frequencies'][0]
if 2400 <= freq <= 2500:
band['name'] = '2.4GHz'
band['band'] = 1
elif 5150 <= freq <= 5900:
band['name'] = '5GHz'
band['band'] = 2
elif 5955 <= freq <= 7115:
band['name'] = '6GHz'
band['band'] = 3
# Set max TX power
if max_power is not None:
result['max_txpower'] = int(max_power)
# Get driver and manufacturer from sysfs
try:
driver_link = subprocess.run(
['readlink', '-f', f'/sys/class/ieee80211/{actual_phy}/device/driver'],
capture_output=True, text=True, timeout=1
).stdout.strip()
if driver_link:
driver_name = driver_link.split('/')[-1]
result['driver'] = driver_name
# Map driver to manufacturer
driver_lower = driver_name.lower()
if 'mt' in driver_lower or 'mediatek' in driver_lower:
result['manufacturer'] = 'MediaTek Inc.'
elif 'rtw' in driver_lower or 'realtek' in driver_lower:
result['manufacturer'] = 'Realtek Semiconductor Corp.'
elif 'ath' in driver_lower or 'qca' in driver_lower:
result['manufacturer'] = 'Qualcomm Atheros'
elif 'iwl' in driver_lower or 'intel' in driver_lower:
result['manufacturer'] = 'Intel Corporation'
elif 'brcm' in driver_lower or 'broadcom' in driver_lower:
result['manufacturer'] = 'Broadcom Inc.'
except Exception:
pass
# Count virtual interfaces
dev_output = run_iw('dev')
if dev_output:
# Extract phy number from actual phy name
phy_num = None
if actual_phy.startswith('radio'):
phy_num = actual_phy[5:]
elif actual_phy.startswith('phy'):
phy_num = actual_phy[3:]
if phy_num:
count = 0
current_phy = None
for line in dev_output.splitlines():
if line.startswith('phy#'):
current_phy = line.replace('phy#', '').strip()
elif current_phy == phy_num and 'Interface' in line:
count += 1
result['num_virtual_interfaces'] = count
return result
def parse_interface_info(ifname):
"""
Parse 'iw dev <name> info' output
Returns: {ifname, iftype, mac, ssid, frequency, channel, txpower, channel_width}
"""
output = run_iw('dev', ifname, 'info')
if not output:
return {}
result = {'ifname': ifname}
for line in output.splitlines():
stripped = line.strip()
# Interface type
if stripped.startswith('type '):
result['iftype'] = stripped.split()[1]
# MAC address
elif stripped.startswith('addr '):
result['mac'] = stripped.split()[1]
# SSID
elif stripped.startswith('ssid '):
result['ssid'] = decode_iw_ssid(' '.join(stripped.split()[1:]))
# Channel/frequency
elif stripped.startswith('channel '):
parts = stripped.split()
if len(parts) >= 2:
result['channel'] = int(parts[1])
if 'MHz' in stripped:
freq_match = re.search(r'\((\d+) MHz', stripped)
if freq_match:
result['frequency'] = int(freq_match.group(1))
# Channel width
if 'width:' in stripped:
width_match = re.search(r'width:\s*(\d+)\s*MHz', stripped)
if width_match:
result['channel_width'] = f"{width_match.group(1)} MHz"
# TX power
elif stripped.startswith('txpower '):
power_match = re.search(r'([0-9.]+) dBm', stripped)
if power_match:
result['txpower'] = float(power_match.group(1))
return result
def parse_stations(ifname):
"""
Parse 'iw dev <name> station dump' output
Returns: list of connected stations with stats
"""
output = run_iw('dev', ifname, 'station', 'dump')
if not output:
return []
stations = []
current = None
for line in output.splitlines():
stripped = line.strip()
# New station entry: "Station aa:bb:cc:dd:ee:ff (on wifiX)"
if stripped.startswith('Station '):
if current:
stations.append(current)
parts = stripped.split()
if len(parts) >= 2:
current = {'mac-address': parts[1].lower()}
else:
current = None
continue
if not current or ':' not in stripped:
continue
key, _, value = stripped.partition(':')
key = key.strip()
value = value.strip()
try:
if key == 'signal':
# Format: "-42 dBm" or "-42 [-44, -45] dBm"
current['signal-strength'] = int(value.split()[0])
elif key == 'connected time':
# Format: "123 seconds"
current['connected-time'] = int(value.split()[0])
elif key == 'rx bytes':
current['rx-bytes'] = value # counter64: string-encoded
elif key == 'tx bytes':
current['tx-bytes'] = value # counter64: string-encoded
elif key == 'rx packets':
current['rx-packets'] = value # counter64: string-encoded
elif key == 'tx packets':
current['tx-packets'] = value # counter64: string-encoded
elif key == 'tx bitrate':
# Format: "866.7 MBit/s ..." - convert to 100kbit/s units
speed_mbps = float(value.split()[0])
current['tx-speed'] = int(speed_mbps * 10)
elif key == 'rx bitrate':
speed_mbps = float(value.split()[0])
current['rx-speed'] = int(speed_mbps * 10)
elif key == 'inactive time':
# Format: "1234 ms"
current['inactive-time'] = int(value.split()[0])
except (ValueError, IndexError):
continue
if current:
stations.append(current)
return stations
def parse_survey(ifname):
"""
Parse 'iw dev <name> survey dump' output
Returns: list of {frequency, in_use, noise, active_time, busy_time, receive_time, transmit_time}
"""
output = run_iw('dev', ifname, 'survey', 'dump')
if not output:
return []
channels = []
current_channel = None
for line in output.splitlines():
stripped = line.strip()
# New survey entry
if stripped.startswith('Survey data from'):
if current_channel:
channels.append(current_channel)
current_channel = None
# Frequency
elif stripped.startswith('frequency:'):
parts = stripped.split()
if len(parts) >= 2:
freq = int(parts[1])
in_use = '[in use]' in stripped
current_channel = {
'frequency': freq,
'in_use': in_use
}
# Channel metrics
elif current_channel:
if stripped.startswith('noise:'):
noise_match = re.search(r'(-?\d+) dBm', stripped)
if noise_match:
current_channel['noise'] = int(noise_match.group(1))
elif stripped.startswith('channel active time:'):
time_match = re.search(r'(\d+) ms', stripped)
if time_match:
current_channel['active_time'] = int(time_match.group(1))
elif stripped.startswith('channel busy time:'):
time_match = re.search(r'(\d+) ms', stripped)
if time_match:
current_channel['busy_time'] = int(time_match.group(1))
elif stripped.startswith('channel receive time:'):
time_match = re.search(r'(\d+) ms', stripped)
if time_match:
current_channel['receive_time'] = int(time_match.group(1))
elif stripped.startswith('channel transmit time:'):
time_match = re.search(r'(\d+) ms', stripped)
if time_match:
current_channel['transmit_time'] = int(time_match.group(1))
# Add last channel
if current_channel:
channels.append(current_channel)
return channels
def parse_list():
"""
Parse 'iw list' output
Returns: list of PHY names
"""
output = run_iw('list')
if not output:
return []
phys = []
for line in output.splitlines():
match = re.match(r'Wiphy (phy\d+|radio\d+)', line)
if match:
phys.append(match.group(1))
return phys
def parse_dev():
"""
Parse 'iw dev' output
Returns: dict mapping PHY numbers to list of interfaces
"""
output = run_iw('dev')
if not output:
return {}
result = {}
current_phy = None
for line in output.splitlines():
# PHY line: "phy#0" or "phy#1"
if line.startswith('phy#'):
current_phy = line.replace('phy#', '').strip()
if current_phy not in result:
result[current_phy] = []
# Interface line: " Interface wlan0"
elif current_phy and 'Interface' in line:
ifname = line.split('Interface')[1].strip()
result[current_phy].append(ifname)
return result
def parse_link(ifname):
"""
Parse 'iw dev <name> link' output for station mode
Returns: {connected, bssid, ssid, frequency, signal, tx_bitrate, rx_bitrate}
"""
output = run_iw('dev', ifname, 'link')
if not output:
return {'connected': False}
if 'Not connected' in output:
return {'connected': False}
result = {'connected': True}
for line in output.splitlines():
stripped = line.strip()
# Connected to aa:bb:cc:dd:ee:ff
if stripped.startswith('Connected to '):
parts = stripped.split()
if len(parts) >= 3:
result['bssid'] = parts[2].lower()
# SSID: NetworkName
elif stripped.startswith('SSID: '):
result['ssid'] = decode_iw_ssid(stripped[6:])
# freq: 5180
elif stripped.startswith('freq: '):
try:
result['frequency'] = int(stripped[6:])
except ValueError:
pass
# signal: -42 dBm
elif stripped.startswith('signal: '):
try:
result['signal-strength'] = int(stripped.split()[1])
except (ValueError, IndexError):
pass
# tx bitrate: 866.7 MBit/s ...
elif stripped.startswith('tx bitrate: '):
try:
speed = float(stripped.split()[2])
result['tx-speed'] = int(speed * 10) # 100kbit/s units
except (ValueError, IndexError):
pass
# rx bitrate: 780.0 MBit/s ...
elif stripped.startswith('rx bitrate: '):
try:
speed = float(stripped.split()[2])
result['rx-speed'] = int(speed * 10)
except (ValueError, IndexError):
pass
return result
def main():
if len(sys.argv) < 2:
print(json.dumps({
'error': 'Usage: iw.py <command> [device]',
'commands': {
'list': 'List all PHY devices',
'dev': 'List all interfaces grouped by PHY',
'info': 'Get PHY or interface information (requires device)',
'survey': 'Get channel survey data (requires interface)',
'station': 'Get connected stations in AP mode (requires interface)',
'link': 'Get link info in station mode (requires interface)'
},
'examples': [
'iw.py list',
'iw.py dev',
'iw.py info radio0',
'iw.py info wlan0',
'iw.py station wifi0',
'iw.py link wlan0',
'iw.py survey wlan0'
]
}, indent=2))
sys.exit(1)
command = sys.argv[1]
try:
if command == 'list':
data = parse_list()
elif command == 'dev':
data = parse_dev()
elif command == 'info':
if len(sys.argv) < 3:
data = {'error': 'info command requires device argument'}
else:
device = sys.argv[2]
# Auto-detect if device is a PHY (phy*/radio*) or interface
if device.startswith('phy') or device.startswith('radio'):
data = parse_phy_info(device)
else:
data = parse_interface_info(device)
elif command == 'station':
if len(sys.argv) < 3:
data = {'error': 'station command requires interface argument'}
else:
data = parse_stations(sys.argv[2])
elif command == 'link':
if len(sys.argv) < 3:
data = {'error': 'link command requires interface argument'}
else:
data = parse_link(sys.argv[2])
elif command == 'survey':
if len(sys.argv) < 3:
data = {'error': 'survey command requires interface argument'}
else:
data = parse_survey(sys.argv[2])
else:
data = {'error': f'Unknown command: {command}'}
print(json.dumps(data, indent=2, ensure_ascii=False))
except Exception as e:
print(json.dumps({'error': str(e)}))
sys.exit(1)
if __name__ == '__main__':
main()
@@ -1,724 +0,0 @@
#!/usr/bin/env python3
"""
WiFi Channel Visualization Tool
Shows graphical representation of WiFi channel overlap and utilization
"""
import sys
import json
import argparse
class Colors:
"""ANSI color codes for terminal output"""
RESET = '\033[0m'
BOLD = '\033[1m'
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
MAGENTA = '\033[95m'
CYAN = '\033[96m'
GRAY = '\033[90m'
BG_RED = '\033[101m'
BG_GREEN = '\033[102m'
BG_YELLOW = '\033[103m'
BG_BLUE = '\033[104m'
BG_GRAY = '\033[100m'
def freq_to_channel(freq):
"""Convert frequency (MHz) to WiFi channel number"""
# 2.4 GHz band
if 2412 <= freq <= 2484:
if freq == 2484:
return 14
return (freq - 2412) // 5 + 1
# 5 GHz band
elif 5170 <= freq <= 5825:
return (freq - 5000) // 5
# 6 GHz band
elif 5955 <= freq <= 7115:
return (freq - 5950) // 5
return None
def get_channel_frequency(channel, band='2.4'):
"""Get center frequency for a channel"""
if band == '2.4':
if channel == 14:
return 2484
return 2412 + (channel - 1) * 5
elif band == '5':
return 5000 + channel * 5
return None
def get_busy_percentage(channel_data):
"""Calculate channel busy percentage"""
active = channel_data.get('active-time', 0)
busy = channel_data.get('busy-time', 0)
if active > 0:
return (busy / active) * 100
return 0
def get_utilization_color(busy_pct):
"""Get color based on channel utilization"""
if busy_pct >= 50:
return Colors.RED
elif busy_pct >= 25:
return Colors.YELLOW
elif busy_pct >= 10:
return Colors.CYAN
else:
return Colors.GREEN
def draw_channel_graph_2_4ghz(survey_data):
"""Draw channel overlap graph for 2.4 GHz band"""
# Parse survey data
channels = {}
in_use_channel = None
for ch_data in survey_data:
freq = ch_data.get('frequency')
ch_num = freq_to_channel(freq)
if ch_num and 1 <= ch_num <= 14:
busy_pct = get_busy_percentage(ch_data)
channels[ch_num] = {
'freq': freq,
'noise': ch_data.get('noise', -100),
'busy': busy_pct,
'in_use': ch_data.get('in-use', False),
'active_time': ch_data.get('active-time', 0),
'busy_time': ch_data.get('busy-time', 0)
}
if ch_data.get('in-use'):
in_use_channel = ch_num
if not channels:
print("No 2.4 GHz channel data available")
return
print(f"\n{Colors.BOLD}2.4 GHz WiFi Channel Overlap Visualization{Colors.RESET}")
print("=" * 80)
print(f"Channel width: 20 MHz | Channel spacing: 5 MHz")
print(f"Non-overlapping channels: 1, 6, 11 (shown in {Colors.GREEN}green{Colors.RESET})")
print()
# Draw frequency scale
print("Frequency (MHz):")
print("2400 2420 2440 2460 2480")
print("|-----------|-----------|-----------|-----------|")
# Draw each channel as a bar showing its 20 MHz width
# Each channel occupies ~4 adjacent channels worth of space
for ch in range(1, 14):
if ch not in channels:
continue
data = channels[ch]
busy_pct = data['busy']
is_in_use = data['in_use']
noise = data['noise']
# Determine color based on status
if is_in_use:
color = Colors.BG_BLUE
marker = ''
elif busy_pct >= 50:
color = Colors.RED
marker = ''
elif busy_pct >= 25:
color = Colors.YELLOW
marker = ''
elif busy_pct > 0:
color = Colors.CYAN
marker = ''
else:
color = Colors.GRAY
marker = '·'
# Non-overlapping channels get green color
if ch in [1, 6, 11] and not is_in_use and busy_pct < 10:
color = Colors.GREEN
# Calculate position (each channel is offset by 5 MHz = 1 position)
# Channel 1 is at 2412 MHz, base is 2400
offset = ((data['freq'] - 2400) // 5)
# Draw channel bar (20 MHz = 4 positions wide)
line = ' ' * 80
line_arr = list(line)
# Mark the channel span (20 MHz width)
for i in range(4):
pos = offset + i - 2 # Center the 20 MHz around channel
if 0 <= pos < len(line_arr):
line_arr[pos] = marker
# Add channel label
label_pos = offset
if 0 <= label_pos < len(line_arr) - 5:
# Clear space for label
for i in range(5):
if label_pos + i < len(line_arr):
line_arr[label_pos + i] = ' '
line = ''.join(line_arr)
# Status indicators
status = ""
if is_in_use:
status = f" {Colors.BOLD}[IN USE]{Colors.RESET}"
busy_color = get_utilization_color(busy_pct)
print(f"{color}Ch{ch:2d}{Colors.RESET} {color}{line}{Colors.RESET} "
f"{busy_color}{busy_pct:5.1f}%{Colors.RESET} "
f"{noise:4d}dBm{status}")
print("\n" + "=" * 80)
print(f"\n{Colors.BOLD}Legend:{Colors.RESET}")
print(f" {Colors.BG_BLUE}██{Colors.RESET} In use (your network)")
print(f" {Colors.RED}▓▓{Colors.RESET} High usage (>50%)")
print(f" {Colors.YELLOW}▒▒{Colors.RESET} Medium usage (25-50%)")
print(f" {Colors.CYAN}░░{Colors.RESET} Low usage (1-25%)")
print(f" {Colors.GRAY}··{Colors.RESET} Idle (<1%)")
print()
def draw_channel_list(survey_data):
"""Draw a simple channel list with utilization bars"""
print(f"\n{Colors.BOLD}Channel Utilization{Colors.RESET}")
print("=" * 80)
print(f"{'Ch':<4} {'Freq':<6} {'Noise':<8} {'Busy%':<8} {'Utilization Bar':<40}")
print("-" * 80)
for ch_data in sorted(survey_data, key=lambda x: x.get('frequency', 0)):
freq = ch_data.get('frequency')
ch_num = freq_to_channel(freq)
if not ch_num:
continue
noise = ch_data.get('noise', -100)
busy_pct = get_busy_percentage(ch_data)
is_in_use = ch_data.get('in-use', False)
# Create utilization bar (40 chars wide = 100%)
bar_length = int(busy_pct * 40 / 100)
bar_color = get_utilization_color(busy_pct)
if is_in_use:
bar = f"{Colors.BG_BLUE}{'' * bar_length}{Colors.RESET}"
marker = f" {Colors.BOLD}◀ IN USE{Colors.RESET}"
else:
bar = f"{bar_color}{'' * bar_length}{Colors.RESET}"
marker = ""
empty = '' * (40 - bar_length)
print(f"{ch_num:<4} {freq:<6} {noise:<8} {busy_pct:5.1f}% {bar}{Colors.GRAY}{empty}{Colors.RESET}{marker}")
print()
def draw_overlap_pie(survey_data):
"""Draw a pie-style visualization of channel group utilization"""
# Parse channel data into 3 non-overlapping groups
# Group 1: channels 1-5 (centered on ch 1)
# Group 2: channels 4-8 (centered on ch 6)
# Group 3: channels 9-13 (centered on ch 11)
channels = {}
in_use_channel = None
for ch_data in survey_data:
freq = ch_data.get('frequency')
ch_num = freq_to_channel(freq)
if ch_num and 1 <= ch_num <= 13:
busy_pct = get_busy_percentage(ch_data)
channels[ch_num] = {
'busy': busy_pct,
'noise': ch_data.get('noise', -100),
'in_use': ch_data.get('in-use', False)
}
if ch_data.get('in-use'):
in_use_channel = ch_num
if not channels:
return
# Calculate group utilization (average of channels in each group)
groups = [
{'name': 'Ch 1', 'channels': [1, 2, 3, 4, 5], 'center': 1},
{'name': 'Ch 6', 'channels': [4, 5, 6, 7, 8], 'center': 6},
{'name': 'Ch 11', 'channels': [9, 10, 11, 12, 13], 'center': 11},
]
for group in groups:
busy_values = [channels.get(ch, {}).get('busy', 0) for ch in group['channels'] if ch in channels]
group['avg_busy'] = sum(busy_values) / len(busy_values) if busy_values else 0
group['center_busy'] = channels.get(group['center'], {}).get('busy', 0)
group['in_use'] = in_use_channel in group['channels'] if in_use_channel else False
total_busy = sum(g['avg_busy'] for g in groups)
print(f"\n{Colors.BOLD}Channel Group Utilization (2.4 GHz){Colors.RESET}")
print("=" * 60)
print("Non-overlapping channel groups with their overlap zones:\n")
# Draw ASCII donut/pie
pie_width = 50
# Calculate proportions
if total_busy > 0:
for group in groups:
group['proportion'] = group['avg_busy'] / total_busy
group['width'] = max(1, int(group['proportion'] * pie_width))
else:
for group in groups:
group['proportion'] = 1/3
group['width'] = pie_width // 3
# Adjust to exactly fill pie_width
total_width = sum(g['width'] for g in groups)
if total_width < pie_width:
groups[0]['width'] += pie_width - total_width
# Draw the pie bar
pie_chars = ['', '', '']
colors = [Colors.GREEN, Colors.YELLOW, Colors.CYAN]
pie_line = ""
for i, group in enumerate(groups):
if group['in_use']:
color = Colors.BG_BLUE
elif group['avg_busy'] >= 50:
color = Colors.RED
elif group['avg_busy'] >= 25:
color = Colors.YELLOW
else:
color = Colors.GREEN
char = pie_chars[i % len(pie_chars)]
pie_line += f"{color}{char * group['width']}{Colors.RESET}"
# Draw centered pie
print(f"{'' * pie_width}")
print(f"{pie_line}")
print(f"{'' * pie_width}")
# Legend with percentages
print()
for i, group in enumerate(groups):
char = pie_chars[i % len(pie_chars)]
if group['in_use']:
color = Colors.BG_BLUE
marker = " ◀ IN USE"
elif group['avg_busy'] >= 50:
color = Colors.RED
marker = ""
elif group['avg_busy'] >= 25:
color = Colors.YELLOW
marker = ""
else:
color = Colors.GREEN
marker = ""
pct_of_total = group['proportion'] * 100
print(f" {color}{char * 3}{Colors.RESET} {group['name']:>5}: "
f"{group['center_busy']:5.1f}% busy (center), "
f"{group['avg_busy']:5.1f}% avg in overlap zone, "
f"{pct_of_total:4.1f}% of total{marker}")
# Draw overlap diagram
print(f"\n{Colors.BOLD}Channel Overlap Diagram:{Colors.RESET}")
print(" Ch: 1 2 3 4 5 6 7 8 9 10 11 12 13")
print(" ╔═══════════════════╗")
print(" G1: ║ 1 ─ 2 ─ 3 ─ 4 ─ 5 ║ (centered on ch 1)")
print(" ╚═══════╦═══════════╝")
print(" ╔═══════════════════╗")
print(" G2: ║ 4 ─ 5 ─ 6 ─ 7 ─ 8 ║ (centered on ch 6)")
print(" ╚═══════════╦═══════╝")
print(" ╔═══════════════════════╗")
print(" G3: ║ 9 ─10 ─11 ─12 ─13 ║ (centered on ch 11)")
print(" ╚═══════════════════════╝")
print()
def generate_svg(survey_data, output_file=None):
"""Generate SVG image(s) showing channel overlap and utilization for both bands"""
# Separate channels by band
channels_2_4 = {}
channels_5 = {}
in_use_2_4 = None
in_use_5 = None
for ch_data in survey_data:
freq = ch_data.get('frequency')
ch_num = freq_to_channel(freq)
if not ch_num:
continue
busy_pct = get_busy_percentage(ch_data)
ch_info = {
'freq': freq,
'busy': busy_pct,
'noise': ch_data.get('noise', -100),
'in_use': ch_data.get('in-use', False)
}
if 2400 <= freq <= 2500:
channels_2_4[ch_num] = ch_info
if ch_info['in_use']:
in_use_2_4 = ch_num
elif 5100 <= freq <= 5900:
channels_5[ch_num] = ch_info
if ch_info['in_use']:
in_use_5 = ch_num
def busy_to_color(busy_pct, is_in_use=False):
if is_in_use:
return "#3b82f6" # Blue
elif busy_pct >= 50:
return "#ef4444" # Red
elif busy_pct >= 25:
return "#f59e0b" # Yellow/Orange
elif busy_pct >= 10:
return "#06b6d4" # Cyan
else:
return "#22c55e" # Green
def generate_band_svg(channels, band, freq_min, freq_max, title, non_overlap_channels=None):
if not channels:
return None
width = 900
height = 400
margin_left = 60
margin_right = 40
margin_top = 60
margin_bottom = 80
chart_width = width - margin_left - margin_right
chart_height = height - margin_top - margin_bottom
def freq_to_x(freq):
return margin_left + (freq - freq_min) / (freq_max - freq_min) * chart_width
def busy_to_height(busy_pct):
return (busy_pct / 100) * chart_height
svg_parts = []
# SVG header
svg_parts.append(f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height}">
<defs>
<style>
.title {{ font: bold 18px sans-serif; fill: #333; }}
.label {{ font: 12px sans-serif; fill: #666; }}
.axis {{ font: 10px sans-serif; fill: #333; }}
.channel-label {{ font: bold 10px sans-serif; fill: #333; }}
.legend {{ font: 12px sans-serif; fill: #333; }}
</style>
</defs>
<!-- Background -->
<rect width="{width}" height="{height}" fill="#fafafa"/>
<!-- Title -->
<text x="{width/2}" y="30" text-anchor="middle" class="title">{title}</text>
<!-- Chart area -->
<rect x="{margin_left}" y="{margin_top}" width="{chart_width}" height="{chart_height}" fill="#fff" stroke="#ddd"/>
''')
# Draw grid lines
for pct in [25, 50, 75, 100]:
y = margin_top + chart_height - busy_to_height(pct)
svg_parts.append(f' <line x1="{margin_left}" y1="{y}" x2="{margin_left + chart_width}" y2="{y}" stroke="#eee" stroke-dasharray="4,4"/>')
svg_parts.append(f' <text x="{margin_left - 5}" y="{y + 4}" text-anchor="end" class="axis">{pct}%</text>')
# Y-axis label
svg_parts.append(f' <text x="15" y="{margin_top + chart_height/2}" text-anchor="middle" transform="rotate(-90, 15, {margin_top + chart_height/2})" class="label">Channel Busy %</text>')
# Draw channels as bars
for ch_num, data in sorted(channels.items()):
center_freq = data['freq']
busy_pct = data['busy']
is_in_use = data['in_use']
# 20 MHz width: ±10 MHz from center
x1 = freq_to_x(center_freq - 10)
x2 = freq_to_x(center_freq + 10)
bar_width = x2 - x1
bar_height = busy_to_height(busy_pct)
bar_y = margin_top + chart_height - bar_height
color = busy_to_color(busy_pct, is_in_use)
opacity = 0.6 if not is_in_use else 0.8
# Draw the channel bar
svg_parts.append(f' <rect x="{x1}" y="{bar_y}" width="{bar_width}" height="{bar_height}" fill="{color}" opacity="{opacity}" stroke="{color}" stroke-width="1"/>')
# Channel label at bottom
label_x = freq_to_x(center_freq)
svg_parts.append(f' <text x="{label_x}" y="{margin_top + chart_height + 15}" text-anchor="middle" class="channel-label">{ch_num}</text>')
# Frequency label (only for some channels to avoid clutter)
if band == '2.4' or ch_num in [36, 52, 100, 149, 165]:
svg_parts.append(f' <text x="{label_x}" y="{margin_top + chart_height + 28}" text-anchor="middle" class="axis">{center_freq}</text>')
# Busy percentage on top of bar (if tall enough)
if bar_height > 20:
svg_parts.append(f' <text x="{label_x}" y="{bar_y + 15}" text-anchor="middle" class="channel-label" fill="white">{busy_pct:.0f}%</text>')
# X-axis labels
svg_parts.append(f' <text x="{margin_left + chart_width/2}" y="{height - 15}" text-anchor="middle" class="label">Channel (Center Frequency MHz)</text>')
# Legend
legend_y = margin_top + 10
legend_x = margin_left + chart_width - 150
legend_items = [
("#3b82f6", "In Use"),
("#ef4444", "High (>50%)"),
("#f59e0b", "Medium (25-50%)"),
("#06b6d4", "Low (10-25%)"),
("#22c55e", "Idle (<10%)"),
]
svg_parts.append(f' <rect x="{legend_x - 10}" y="{legend_y - 5}" width="160" height="{len(legend_items) * 18 + 10}" fill="white" stroke="#ddd" rx="4"/>')
for i, (color, label) in enumerate(legend_items):
y = legend_y + 10 + i * 18
svg_parts.append(f' <rect x="{legend_x}" y="{y - 8}" width="12" height="12" fill="{color}" opacity="0.7"/>')
svg_parts.append(f' <text x="{legend_x + 18}" y="{y + 2}" class="legend">{label}</text>')
# Non-overlapping channels note (for 2.4 GHz)
if non_overlap_channels:
svg_parts.append(f' <text x="{margin_left + 5}" y="{margin_top + chart_height + 50}" class="label">Non-overlapping: Ch {", ".join(map(str, non_overlap_channels))}</text>')
for ch in non_overlap_channels:
if ch in channels:
center_freq = channels[ch]['freq']
x = freq_to_x(center_freq)
svg_parts.append(f' <circle cx="{x}" cy="{margin_top + chart_height + 40}" r="8" fill="none" stroke="#22c55e" stroke-width="2"/>')
svg_parts.append(f' <text x="{x}" y="{margin_top + chart_height + 44}" text-anchor="middle" class="channel-label" fill="#22c55e">{ch}</text>')
else:
svg_parts.append(f' <text x="{margin_left + 5}" y="{margin_top + chart_height + 50}" class="label">All channels non-overlapping (20 MHz spacing)</text>')
svg_parts.append('</svg>')
return '\n'.join(svg_parts)
# Generate SVGs for each band
svg_2_4 = generate_band_svg(channels_2_4, '2.4', 2400, 2485,
"2.4 GHz WiFi Channel Overlap &amp; Utilization",
[1, 6, 11])
svg_5 = generate_band_svg(channels_5, '5', 5150, 5850,
"5 GHz WiFi Channel Utilization",
None)
# Combine or output separately
if svg_2_4 and svg_5:
# Combine into one SVG with both bands stacked
combined = f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 820">
<g transform="translate(0, 0)">
{svg_2_4.replace('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 400">', '').replace('</svg>', '')}
</g>
<g transform="translate(0, 410)">
{svg_5.replace('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 400">', '').replace('</svg>', '')}
</g>
</svg>'''
svg_content = combined
elif svg_2_4:
svg_content = svg_2_4
elif svg_5:
svg_content = svg_5
else:
return None
if output_file:
with open(output_file, 'w') as f:
f.write(svg_content)
print(f"SVG written to: {output_file}")
else:
print(svg_content)
return svg_content
def draw_recommendations(survey_data, json_output=False):
"""Analyze channels and provide recommendations"""
# Parse channel data
channels = {}
in_use_channel = None
for ch_data in survey_data:
freq = ch_data.get('frequency')
ch_num = freq_to_channel(freq)
if ch_num:
busy_pct = get_busy_percentage(ch_data)
channels[ch_num] = {
'busy': busy_pct,
'noise': ch_data.get('noise', -100),
'in_use': ch_data.get('in-use', False)
}
if ch_data.get('in-use'):
in_use_channel = ch_num
# Find least congested non-overlapping channels
best_channels = []
for ch in [1, 6, 11]:
if ch in channels:
best_channels.append((ch, channels[ch]['busy']))
best_channels.sort(key=lambda x: x[1])
# JSON output
if json_output:
output = {
"recommended_channels": [
{"channel": ch, "busy_percent": round(busy, 1)}
for ch, busy in best_channels
]
}
if in_use_channel:
output["current_channel"] = in_use_channel
output["current_busy_percent"] = round(channels.get(in_use_channel, {}).get('busy', 0), 1)
print(json.dumps(output, indent=2))
return
# Text output
print(f"\n{Colors.BOLD}Channel Recommendations{Colors.RESET}")
print("=" * 80)
if in_use_channel:
print(f"Current channel: {Colors.BOLD}{in_use_channel}{Colors.RESET}")
current_busy = channels.get(in_use_channel, {}).get('busy', 0)
if current_busy > 50:
print(f" {Colors.RED}{Colors.RESET} High congestion detected ({current_busy:.1f}% busy)")
elif current_busy > 25:
print(f" {Colors.YELLOW}{Colors.RESET} Moderate congestion ({current_busy:.1f}% busy)")
else:
print(f" {Colors.GREEN}{Colors.RESET} Good channel utilization ({current_busy:.1f}% busy)")
print(f"\nRecommended non-overlapping channels (2.4 GHz):")
for i, (ch, busy) in enumerate(best_channels[:3], 1):
color = get_utilization_color(busy)
marker = "" if i == 1 else " "
print(f" {marker} Channel {ch:2d}: {color}{busy:5.1f}% busy{Colors.RESET}")
print()
def main():
parser = argparse.ArgumentParser(
description='Visualize WiFi channel overlap and utilization',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
Examples:
# Read from yanger output (show all sections)
yanger -x "ixll -A ssh host sudo" ietf-hardware | %(prog)s
# Read from file
%(prog)s survey_data.json
# Show only list view
%(prog)s --list survey_data.json
# Show only specific sections
%(prog)s --overlap survey_data.json
%(prog)s --pie survey_data.json
%(prog)s --utilization survey_data.json
%(prog)s --recommendations survey_data.json
%(prog)s --overlap --pie survey_data.json
# Output recommendations as JSON
%(prog)s --recommendations --json survey_data.json
# Generate SVG image
%(prog)s --svg /tmp/wifi-channels.svg survey_data.json
%(prog)s --svg - survey_data.json > output.svg
'''
)
parser.add_argument('file', nargs='?', help='JSON file with hardware data (default: stdin)')
parser.add_argument('--list', action='store_true', help='Show simple list view instead of overlap graph')
parser.add_argument('--no-color', action='store_true', help='Disable colors')
parser.add_argument('--json', action='store_true', help='Output recommendations in JSON format')
parser.add_argument('--svg', metavar='FILE', help='Generate SVG image to FILE (use - for stdout)')
# Section filters
parser.add_argument('--overlap', action='store_true', help='Show only channel overlap visualization (2.4 GHz)')
parser.add_argument('--pie', action='store_true', help='Show only channel group pie chart (2.4 GHz)')
parser.add_argument('--utilization', action='store_true', help='Show only channel utilization list')
parser.add_argument('--recommendations', action='store_true', help='Show only channel recommendations')
args = parser.parse_args()
# Disable colors if requested
if args.no_color:
for attr in dir(Colors):
if not attr.startswith('_'):
setattr(Colors, attr, '')
# Read input
if args.file:
with open(args.file, 'r') as f:
data = json.load(f)
else:
data = json.load(sys.stdin)
# Extract survey data from hardware components
survey_data = []
hardware = data.get('ietf-hardware:hardware', {})
components = hardware.get('component', [])
for component in components:
if component.get('class') == 'infix-hardware:wifi':
wifi_radio = component.get('infix-hardware:wifi-radio', {})
survey = wifi_radio.get('survey', {})
channels = survey.get('channel', [])
if channels:
survey_data.extend(channels)
if not survey_data:
print("No WiFi survey data found in input", file=sys.stderr)
print("Expected format: yanger ietf-hardware output with wifi-radio survey data", file=sys.stderr)
sys.exit(1)
# Generate SVG if requested (exclusive mode)
if args.svg:
output_file = None if args.svg == '-' else args.svg
generate_svg(survey_data, output_file)
return
# Determine which sections to show
# If no section flags are set, show all sections
show_all = not (args.overlap or args.pie or args.utilization or args.recommendations)
show_overlap = show_all or args.overlap
show_pie = show_all or args.pie
show_utilization = show_all or args.utilization
show_recommendations_section = show_all or args.recommendations
# Draw visualization
freqs = [ch.get('frequency', 0) for ch in survey_data]
has_2_4ghz = any(2400 <= f <= 2500 for f in freqs)
if show_overlap and has_2_4ghz and not args.list:
draw_channel_graph_2_4ghz(survey_data)
if show_pie and has_2_4ghz:
draw_overlap_pie(survey_data)
if show_utilization:
draw_channel_list(survey_data)
if show_recommendations_section:
draw_recommendations(survey_data, json_output=args.json)
if __name__ == '__main__':
main()
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
if [ $# -ne 1 ]; then
echo "usage: $0 <ifname>"
exit 1
fi
ifname=$1
TIMEOUT=300
status=$(wpa_cli -i $ifname scan)
while [ "$status" != "OK" ]; do
status=$(wpa_cli -i $ifname scan)
TIMEOUT=$((TIMEOUT-1))
[ $TIMEOUT -eq 0 ] && logger -t wifi-scanner "Failed to start scanning $ifname" && exit 1
sleep 0.5
done
-242
View File
@@ -1,242 +0,0 @@
#!/bin/sh
# DHCPv6 client state update script for odhcp6c
# This script expects a system with resolvconf (openresolv) and iproute2
[ -z "$1" ] && echo "Error: should be called from odhcp6c" && exit 1
interface="$1"
state="$2"
RESOLV_CONF="/run/resolvconf/interfaces/${interface}-ipv6.conf"
NTPFILE="/run/chrony/dhcp-sources.d/${interface}-ipv6.sources"
[ -n "$metric" ] || metric=5
log()
{
logger -I $$ -t odhcp6c -p user.notice "${interface}: $*"
}
dbg()
{
logger -I $$ -t odhcp6c -p user.debug "${interface}: $*"
}
err()
{
logger -I $$ -t odhcp6c -p user.err "${interface}: $*"
}
teardown_interface()
{
ip -6 route flush dev "$interface"
ip -6 address flush dev "$interface" scope global
}
setup_interface()
{
# Merge RA addresses with DHCP addresses
for entry in $RA_ADDRESSES; do
duplicate=0
addr="${entry%%/*}"
for dentry in $ADDRESSES; do
daddr="${dentry%%/*}"
[ "$addr" = "$daddr" ] && duplicate=1
done
[ "$duplicate" = "0" ] && ADDRESSES="$ADDRESSES $entry"
done
# Add addresses
for entry in $ADDRESSES; do
addr="${entry%%,*}"
entry="${entry#*,}"
preferred="${entry%%,*}"
entry="${entry#*,}"
valid="${entry%%,*}"
ip -6 address add "$addr" dev "$interface" preferred_lft "$preferred" valid_lft "$valid" proto dhcp
log "assigned address $addr (preferred=$preferred, valid=$valid)"
done
# Add routes from RA
for entry in $RA_ROUTES; do
addr="${entry%%,*}"
entry="${entry#*,}"
gw="${entry%%,*}"
entry="${entry#*,}"
valid="${entry%%,*}"
entry="${entry#*,}"
metric="${entry%%,*}"
if [ -n "$gw" ]; then
ip -6 route add "$addr" via "$gw" metric "$metric" dev "$interface" from "::/128"
else
ip -6 route add "$addr" metric "$metric" dev "$interface"
fi
# Add routes for delegated prefixes
for prefix in $PREFIXES; do
paddr="${prefix%%,*}"
[ -n "$gw" ] && ip -6 route add "$addr" via "$gw" metric "$metric" dev "$interface" from "$paddr"
done
done
}
handle_prefixes()
{
# $PREFIXES format: "prefix/len,preferred,valid[,class=N][,excluded=...] ..."
for entry in $PREFIXES; do
addr="${entry%%,*}"
entry="${entry#*,}"
preferred="${entry%%,*}"
entry="${entry#*,}"
valid="${entry%%,*}"
log "received delegated prefix $addr (preferred=$preferred, valid=$valid)"
# Add unreachable route to prevent routing loops
ip -6 route add unreachable "$addr" 2>/dev/null
# Future: Distribute to downstream interfaces
done
}
handle_dns()
{
truncate -s 0 "$RESOLV_CONF"
# Combine DHCPv6 DNS ($RDNSS) and RA DNS ($RA_DNS), deduplicating
all_dns=""
for server in $RDNSS $RA_DNS; do
# Simple deduplication: only add if not already in list
case " $all_dns " in
*" $server "*) ;;
*) all_dns="$all_dns $server" ;;
esac
done
# Domain search list (DHCPv6 option 24)
if [ -n "$DOMAINS" ]; then
dbg "adding search domains: $DOMAINS"
echo "search $DOMAINS # $interface" >> "$RESOLV_CONF"
fi
# DNS servers
for server in $all_dns; do
[ -z "$server" ] && continue
dbg "adding dns $server"
echo "nameserver $server # $interface" >> "$RESOLV_CONF"
done
if [ -n "$all_dns" ]; then
resolvconf -u
fi
}
handle_ntp()
{
# DHCPv6 option 56 (NTP server) is provided as $OPTION_56 in hex format
# Format: sub-option-code (2 bytes) + length (2 bytes) + data
# Sub-option 1 = NTP server address (16 bytes IPv6)
#
# This is complex to parse in shell. For now, we attempt basic parsing
# and fall back to logging a warning if the format is unexpected.
if [ -n "$OPTION_56" ]; then
# Remove all non-hex characters (spaces, colons, etc.) and convert to lowercase
hex=$(echo "$OPTION_56" | tr -d '[:space:]:-' | tr '[:upper:]' '[:lower:]')
truncate -s 0 "$NTPFILE"
ntp_found=0
# Parse option 56: iterate through sub-options
# Each sub-option: 2 bytes code + 2 bytes length + data
pos=0
while [ $pos -lt ${#hex} ]; do
# Need at least 4 hex chars (2 bytes) for sub-option code
[ $((${#hex} - pos)) -lt 4 ] && break
# Extract sub-option code (2 bytes = 4 hex chars)
subopt_code=$(echo "$hex" | cut -c $((pos+1))-$((pos+4)))
pos=$((pos + 4))
# Need 4 more hex chars for length
[ $((${#hex} - pos)) -lt 4 ] && break
# Extract length (2 bytes = 4 hex chars)
subopt_len_hex=$(echo "$hex" | cut -c $((pos+1))-$((pos+4)))
subopt_len=$(printf "%d" "0x$subopt_len_hex")
pos=$((pos + 4))
# Sub-option 1 = NTP server address (should be 16 bytes for IPv6)
if [ "$subopt_code" = "0001" ] && [ "$subopt_len" -eq 16 ]; then
# Extract 16 bytes (32 hex chars) for IPv6 address
addr_hex=$(echo "$hex" | cut -c $((pos+1))-$((pos+32)))
# Convert hex to IPv6 address format
# Format: 0123456789abcdef0123456789abcdef -> 0123:4567:89ab:cdef:0123:4567:89ab:cdef
ipv6=$(echo "$addr_hex" | sed 's/\(....\)\(....\)\(....\)\(....\)\(....\)\(....\)\(....\)\(....\)/\1:\2:\3:\4:\5:\6:\7:\8/')
dbg "got NTP server $ipv6"
echo "server $ipv6 iburst" >> "$NTPFILE"
ntp_found=1
fi
# Skip this sub-option's data
pos=$((pos + subopt_len * 2))
done
if [ "$ntp_found" -eq 1 ]; then
chronyc reload sources >/dev/null 2>&1
else
dbg "option 56 received but no NTP server addresses found (consider using option 31/SNTP)"
fi
fi
}
log "state: $state"
(
flock 9
case "$state" in
started)
# Initial state - clean up any stale config
teardown_interface
;;
bound)
# Fresh lease - tear down and set up from scratch
teardown_interface
setup_interface
handle_prefixes
handle_dns
handle_ntp
;;
informed|updated|rebound|ra-updated)
# Update existing configuration
setup_interface
[ -n "$PREFIXES" ] && handle_prefixes
handle_dns
handle_ntp
;;
unbound|stopped)
# Lost server or client stopped
teardown_interface
rm -f "$RESOLV_CONF"
rm -f "$NTPFILE"
resolvconf -u
chronyc reload sources >/dev/null 2>&1
;;
esac
) 9>/tmp/odhcp6c.lock.${interface}
rm -f /tmp/odhcp6c.lock.${interface}
# Run hooks
HOOK_DIR="/usr/libexec/odhcp6c.d"
for hook in "${HOOK_DIR}/"*; do
[ -f "${hook}" -a -x "${hook}" ] || continue
"${hook}" "$interface" "$state"
done
exit 0
+2 -22
View File
@@ -411,20 +411,10 @@ create()
logging="--log-driver syslog"
fi
# Build resource limit arguments
resource=""
if [ -n "$memory" ]; then
resource="$resource --memory=$memory"
fi
if [ -n "$cpu_limit" ]; then
resource="$resource --cpu-quota=$cpu_limit"
fi
# When we get here we've already fetched, or pulled, the image
args="$args --read-only --replace --quiet $caps"
args="$args --cgroups=enabled --cgroupns=host --cgroup-parent=system/container@$name"
args="$args --read-only --replace --quiet --cgroup-parent=containers $caps"
args="$args --restart=$restart --systemd=false --tz=local $privileged"
args="$args $vol $mount $hostname $entrypoint $env $port $logging $resource"
args="$args $vol $mount $hostname $entrypoint $env $port $logging"
pidfile=/run/container:${name}.pid
[ -n "$quiet" ] || log "---------------------------------------"
@@ -726,8 +716,6 @@ options:
--log-path PATH Path for k8s-file log pipe
-m, --mount HOST:DEST Bind mount a read-only file inside a container
--manual Do not start container automatically after creation
--memory BYTES Memory limit in bytes (supports K/M/G suffix)
--cpu-limit LIMIT CPU limit in millicores (1000m = 100% of 1 core)
-n, --name NAME Alternative way of supplying name to start/stop/restart
--privileged Give container extended privileges
-p, --publish PORT Publish ports when creating container
@@ -848,14 +836,6 @@ while [ "$1" != "" ]; do
--manual)
manual=true
;;
--memory)
shift
memory="$1"
;;
--cpu-limit)
shift
cpu_limit="$1"
;;
-n | --name)
shift
name="$1"
+111
View File
@@ -0,0 +1,111 @@
#!/bin/sh
# This script expects a system with resolvconf (openresolv) and iproute2
[ -z "$1" ] && echo "Error: should be called from udhcpc6" && exit 1
ACTION="$1"
RESOLV_CONF="/run/resolvconf/interfaces/${interface}-ipv6.conf"
NTPFILE="/run/chrony/dhcp-sources.d/${interface}-ipv6.sources"
[ -n "$metric" ] || metric=5
if [ -z "${IF_WAIT_DELAY}" ]; then
IF_WAIT_DELAY=10
fi
log()
{
logger -I $$ -t udhcpc6 -p user.notice "${interface}: $*"
}
dbg()
{
logger -I $$ -t udhcpc6 -p user.debug "${interface}: $*"
}
err()
{
logger -I $$ -t udhcpc6 -p user.err "${interface}: $*"
}
clr_dhcpv6_addresses()
{
addrs=$(ip -j addr show dev $interface \
| jq -c '.[0].addr_info[] | select(.family == "inet6") | select(.protocol == "dhcp")')
for addr in $addrs; do
ip="$(echo "$addr" | jq -r '."local"')"
prefix="$(echo "$addr" | jq -r '."prefixlen"')"
log "removing $ip/$prefix"
ip addr del "$ip/$prefix" dev "$interface"
done
}
log "action $ACTION"
case "$ACTION" in
deconfig)
clr_dhcpv6_addresses
# drop info from this interface
rm -f "$RESOLV_CONF"
rm -f "$NTPFILE"
;;
leasefail|nak)
# DHCPv6 lease failed - log it
err "DHCPv6 lease failed"
;;
renew|bound)
# Add IPv6 address if provided (stateful DHCPv6)
if [ -n "$ipv6" ]; then
if /bin/ip addr add dev $interface $ipv6 proto dhcp; then
log "assigned address $ipv6"
fi
fi
# Handle delegated prefix (prefix delegation)
if [ -n "$ipv6prefix" ]; then
log "received delegated prefix $ipv6prefix"
# Prefix delegation handling could be added here
# For now, just log it - actual routing/distribution
# would need additional configuration
fi
# drop info from this interface
truncate -s 0 "$RESOLV_CONF"
# DHCPv6 domain search list (option 24)
if [ -n "$search" ]; then
dbg "adding search $search"
echo "search $search # $interface" >> $RESOLV_CONF
fi
# DHCPv6 DNS servers (option 23)
if [ -n "$dns" ]; then
for i in $dns ; do
dbg "adding dns $i"
echo "nameserver $i # $interface" >> $RESOLV_CONF
done
resolvconf -u
fi
# NTP servers (option 56)
if [ -n "$ntpsrv" ]; then
truncate -s 0 "$NTPFILE"
for srv in $ntpsrv; do
dbg "got NTP server $srv"
echo "server $srv iburst" >> "$NTPFILE"
done
chronyc reload sources >/dev/null
fi
;;
esac
HOOK_DIR="$0.d"
for hook in "${HOOK_DIR}/"*; do
[ -f "${hook}" -a -x "${hook}" ] || continue
"${hook}" "$ACTION"
done
exit 0
+1 -10
View File
@@ -358,7 +358,6 @@ CONFIG_SND_SOC_JH7110_TDM=y
CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
@@ -473,16 +472,8 @@ CONFIG_DEBUG_FS=y
# CONFIG_SLUB_DEBUG is not set
CONFIG_DEBUG_RODATA_TEST=y
CONFIG_DEBUG_WX=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=20
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_WQ_WATCHDOG=y
CONFIG_WQ_CPU_INTENSIVE_REPORT=y
CONFIG_TEST_LOCKUP=m
# CONFIG_SCHED_DEBUG is not set
CONFIG_STACKTRACE=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
+8 -82
View File
@@ -53,6 +53,7 @@ CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_IPV6_SIT=m
@@ -68,31 +69,12 @@ CONFIG_BRIDGE_NETFILTER=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_ZONES=y
CONFIG_NF_CONNTRACK_PROCFS=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_AMANDA=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_H323=y
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
CONFIG_NF_CONNTRACK_SNMP=y
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SANE=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NF_CT_NETLINK_TIMEOUT=y
CONFIG_NF_CT_NETLINK_HELPER=y
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=y
CONFIG_NFT_CT=m
CONFIG_NFT_FLOW_OFFLOAD=y
CONFIG_NFT_CONNLIMIT=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
@@ -101,23 +83,15 @@ CONFIG_NFT_REDIR=m
CONFIG_NFT_NAT=m
CONFIG_NFT_TUNNEL=m
CONFIG_NFT_QUEUE=m
CONFIG_NFT_QUOTA=y
CONFIG_NFT_REJECT=m
CONFIG_NFT_COMPAT=m
CONFIG_NFT_HASH=m
CONFIG_NFT_FIB_INET=y
CONFIG_NFT_XFRM=m
CONFIG_NFT_SOCKET=m
CONFIG_NFT_OSF=m
CONFIG_NFT_TPROXY=y
CONFIG_NFT_SYNPROXY=y
CONFIG_NFT_DUP_NETDEV=m
CONFIG_NFT_FWD_NETDEV=m
CONFIG_NFT_FIB_NETDEV=y
CONFIG_NFT_REJECT_NETDEV=m
CONFIG_NF_FLOW_TABLE_INET=y
CONFIG_NF_FLOW_TABLE=y
CONFIG_NETFILTER_XTABLES_LEGACY=y
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_TARGET_LOG=m
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
@@ -134,69 +108,29 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_IP_SET=y
CONFIG_IP_SET_BITMAP_IP=y
CONFIG_IP_SET_BITMAP_IPMAC=y
CONFIG_IP_SET_BITMAP_PORT=y
CONFIG_IP_SET_HASH_IP=y
CONFIG_IP_SET_HASH_IPMARK=y
CONFIG_IP_SET_HASH_IPPORT=y
CONFIG_IP_SET_HASH_IPPORTIP=y
CONFIG_IP_SET_HASH_IPPORTNET=y
CONFIG_IP_SET_HASH_IPMAC=y
CONFIG_IP_SET_HASH_MAC=y
CONFIG_IP_SET_HASH_NETPORTNET=y
CONFIG_IP_SET_HASH_NET=y
CONFIG_IP_SET_HASH_NETNET=y
CONFIG_IP_SET_HASH_NETPORT=y
CONFIG_IP_SET_HASH_NETIFACE=y
CONFIG_IP_SET_LIST_SET=y
CONFIG_NFT_DUP_IPV4=y
CONFIG_NFT_FIB_IPV4=y
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_LOG_ARP=y
CONFIG_NF_LOG_IPV4=y
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_RPFILTER=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_SYNPROXY=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_NETMAP=m
CONFIG_IP_NF_TARGET_REDIRECT=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_NFT_DUP_IPV6=y
CONFIG_NFT_FIB_IPV6=y
CONFIG_IP_NF_MANGLE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_MH=m
CONFIG_IP6_NF_MATCH_RPFILTER=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_MATCH_SRH=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_TARGET_SYNPROXY=m
CONFIG_IP6_NF_RAW=m
CONFIG_IP6_NF_NAT=m
CONFIG_IP6_NF_TARGET_MASQUERADE=m
CONFIG_IP6_NF_TARGET_NPT=m
CONFIG_NF_TABLES_BRIDGE=m
CONFIG_NFT_BRIDGE_META=m
CONFIG_NFT_BRIDGE_REJECT=m
CONFIG_NF_CONNTRACK_BRIDGE=m
CONFIG_BRIDGE_NF_EBTABLES=m
CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
@@ -257,7 +191,6 @@ CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_NETDEVICES=y
CONFIG_BONDING=m
CONFIG_DUMMY=m
CONFIG_WIREGUARD=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
CONFIG_IPVLAN=m
@@ -287,7 +220,6 @@ CONFIG_WATCHDOG_SYSFS=y
CONFIG_SOFT_WATCHDOG=y
CONFIG_I6300ESB_WDT=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_XHCI_HCD=m
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_UHCI_HCD=m
@@ -331,13 +263,7 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=20
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_WQ_CPU_INTENSIVE_REPORT=y
CONFIG_TEST_LOCKUP=m
CONFIG_FUNCTION_TRACER=y
CONFIG_UNWINDER_FRAME_POINTER=y
+3 -10
View File
@@ -29,13 +29,12 @@ 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.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.58"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch32/linux_defconfig"
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_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@@ -60,7 +59,7 @@ BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_ONIGURUMA=y
BR2_PACKAGE_AVAHI_DAEMON=y
@@ -83,7 +82,6 @@ BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_GETENT=y
@@ -97,12 +95,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -141,6 +133,7 @@ BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_ONIEPROM=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
IMAGE_ITB_AUX=y
+3 -10
View File
@@ -29,13 +29,12 @@ 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.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.58"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/aarch32/linux_defconfig"
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_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@@ -60,7 +59,7 @@ BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_ONIGURUMA=y
BR2_PACKAGE_AVAHI_DAEMON=y
@@ -83,7 +82,6 @@ BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_GETENT=y
@@ -97,12 +95,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -141,6 +133,7 @@ BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_ONIEPROM=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
IMAGE_ITB_AUX=y
+5 -12
View File
@@ -27,17 +27,17 @@ BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNA
BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.61"
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_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW=y
BR2_PACKAGE_LINUX_FIRMWARE_RTL_8169=y
BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
@@ -63,7 +63,7 @@ BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
BR2_PACKAGE_ONIGURUMA=y
@@ -102,7 +102,6 @@ BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_TRACEROUTE=y
BR2_PACKAGE_ULOGD=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_NEOFETCH=y
BR2_PACKAGE_SUDO=y
@@ -120,12 +119,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -149,8 +142,7 @@ BR2_PACKAGE_MARVELL_CN9130_CRB=y
BR2_PACKAGE_MARVELL_ESPRESSOBIN=y
BR2_PACKAGE_RASPBERRYPI_RPI64=y
BR2_PACKAGE_STYX_DCP_SC_28P=y
BR2_PACKAGE_FEATURE_WIFI_MEDIATEK=y
BR2_PACKAGE_FEATURE_WIFI_REALTEK=y
BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK=y
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_CURIOS_HTTPD=y
@@ -179,6 +171,7 @@ 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
+6 -10
View File
@@ -26,17 +26,19 @@ BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNA
BR2_ROOTFS_POST_BUILD_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.61"
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_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW=y
BR2_PACKAGE_LINUX_FIRMWARE_RTL_8169=y
BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_DBUS_TRIGGERD=y
@@ -83,7 +85,6 @@ BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_KMOD_TOOLS=y
@@ -96,12 +97,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -128,6 +123,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
+2 -8
View File
@@ -37,7 +37,6 @@ 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_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@@ -76,7 +75,7 @@ BR2_PACKAGE_LIBINPUT=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
BR2_PACKAGE_ONIGURUMA=y
@@ -132,12 +131,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -203,6 +196,7 @@ 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
+6 -11
View File
@@ -26,13 +26,12 @@ BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNA
BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.61"
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
BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_JQ=y
@@ -51,6 +50,7 @@ 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
@@ -59,7 +59,7 @@ BR2_PACKAGE_LIBOPENSSL_BIN=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_NETOPEER2_CLI=y
BR2_PACKAGE_NSS_MDNS=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_LINUX_PAM=y
BR2_PACKAGE_LIBPAM_RADIUS_AUTH=y
BR2_PACKAGE_ONIGURUMA=y
@@ -70,6 +70,7 @@ BR2_PACKAGE_CONNTRACK_TOOLS=y
BR2_PACKAGE_DNSMASQ=y
BR2_PACKAGE_ETHTOOL=y
BR2_PACKAGE_FPING=y
BR2_PACKAGE_FIREWALL=y
BR2_PACKAGE_FRR=y
# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set
BR2_PACKAGE_IPERF3=y
@@ -82,6 +83,7 @@ BR2_PACKAGE_MTR=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
@@ -96,7 +98,6 @@ BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_TRACEROUTE=y
BR2_PACKAGE_ULOGD=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_NEOFETCH=y
BR2_PACKAGE_SUDO=y
@@ -114,12 +115,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -160,7 +155,6 @@ 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_FIREWALL=y
BR2_PACKAGE_IITO=y
BR2_PACKAGE_KEYACK=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
@@ -174,6 +168,7 @@ 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
+3 -10
View File
@@ -26,16 +26,15 @@ BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNA
BR2_ROOTFS_POST_BUILD_SCRIPT="board/qemu/x86_64/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.7"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.61"
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
BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
BR2_PACKAGE_BUSYBOX_CONFIG="${BR2_EXTERNAL_INFIX_PATH}/board/common/busybox_defconfig"
BR2_PACKAGE_ODHCP6C=y
BR2_PACKAGE_STRACE=y
BR2_PACKAGE_STRESS_NG=y
BR2_PACKAGE_SYSREPO_GROUP="sysrepo"
BR2_PACKAGE_SYSREPO_GROUP="sys-cli"
BR2_PACKAGE_JQ=y
BR2_PACKAGE_E2FSPROGS=y
BR2_PACKAGE_DBUS_CXX=y
@@ -81,7 +80,6 @@ BR2_PACKAGE_OPENSSH=y
BR2_PACKAGE_SOCAT=y
BR2_PACKAGE_TCPDUMP=y
BR2_PACKAGE_WHOIS=y
BR2_PACKAGE_WIREGUARD_TOOLS=y
BR2_PACKAGE_BASH_COMPLETION=y
BR2_PACKAGE_SUDO=y
BR2_PACKAGE_GETENT=y
@@ -95,12 +93,6 @@ BR2_PACKAGE_RAUC_JSON=y
BR2_PACKAGE_SYSKLOGD=y
BR2_PACKAGE_SYSKLOGD_LOGGER=y
BR2_PACKAGE_WATCHDOGD=y
BR2_PACKAGE_WATCHDOGD_GENERIC=y
BR2_PACKAGE_WATCHDOGD_LOADAVG=y
BR2_PACKAGE_WATCHDOGD_FILENR=y
BR2_PACKAGE_WATCHDOGD_MEMINFO=y
BR2_PACKAGE_WATCHDOGD_FSMON=y
BR2_PACKAGE_WATCHDOGD_TEMPMON=y
BR2_PACKAGE_LESS=y
BR2_PACKAGE_MG=y
BR2_PACKAGE_NANO=y
@@ -143,6 +135,7 @@ BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
BR2_PACKAGE_ONIEPROM=y
BR2_PACKAGE_SHOW=y
BR2_PACKAGE_ROUSETTE=y
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
IMAGE_ITB_AUX=y
+5 -63
View File
@@ -6,80 +6,22 @@ All notable changes to the project are documented in this file.
[v26.01.0][UNRELEASED]
-------------------------
> [!IMPORTANT]
> This release includes **breaking changes** to WiFi configuration that will
> result in existing configuration being disabled:
>
> - WiFi station/client configuration has been restructured. The `wifi` container
> now requires a `radio` reference, and station configuration has moved under a
> `wifi/station` container. Existing WiFi configurations must be manually updated
> - WiFi radios are now configured via `ietf-hardware` instead of the interfaces module
>
> Also, **Raspberry Pi users must upgrade the bootloader** before upgrading to
> this release. We recommend backing up your `startup-config.cfg` and reflash
> the SD card with a new [sd card image][].
### Changes
Noteworthy changes and additions in this release are marked below in bold text.
- Upgrade **Linux kernel to 6.18.7** (LTS)
- Upgrade Buildroot to 2025.02.10 (LTS)
- Upgrade libyang to 4.2.2
- Upgrade sysrepo to 4.2.10
- Upgrade netopeer2 (NETCONF) to 2.7.0
- Add **RIPv2 routing support**, issue #582
- Add **NTP server support**, issue #904
- Migrate DHCPv6 client to odhcp6c for improved Router Advertisement
integration. Adds support for hybrid RA+DHCPv6 deployments where SLAAC
assigns addresses and DHCPv6 provides DNS (common ISP scenario)
- Upgrade Linux kernel to 6.12.61 (LTS)
- Add RIPv2 routing support, issue #582
- Add support for configurable OSPF debug logging, issue #1281. Debug options
can now be enabled per category (bfd, packet, ism, nsm, default-information,
nssa). All debug options are disabled by default to prevent log flooding in
production environments. See the documentation for usage examples
- Add support for configurable container resource limits, memory and CPU.
Resource usage is available through the operational datastore, where the
currently active resource limits in the container runtime are also available
- Add support for "routing interfaces", issue #647. Lists interfaces with IP
forwarding. Inspect from CLI using `show interface`, look for `⇅` flag
- Add operational data journal to statd with hierarchical time-based retention
policy, keeping snapshots from every 5 minutes (recent) to yearly (historical)
- Add support data collection script, useful when troubleshooting issues on
deployed systems. Gathers system information, logs, and more. Issue #1287
- Add **WiFi Access Point (AP) mode with multi-SSID support and WPA2/WPA3**
security. **BREAKING:** WiFi architecture refactored with radios configured
via `ietf-hardware` and interfaces requiring `radio` reference. Station
config moved to `wifi/station` container. Existing Wi-Fi interfaces will be
removed during upgrade (for the rest of the configuration to apply) and you
need to reconfigure them again. See the [WiFi][] documentation for details
- Add support for **WireGuard VPN tunnels**.
- New default NACM privilege levels (user levels) in `factory-config`:
`operator` (network & container manager) and `guest` (read-only). For
details, see the updated system configuration documentation, as well as a
new dedicated NACM configuration guide
- New `show nacm` admin-exec command to inspect access control rules
- CLI now supports Ctrl-@ and Ctrl-w/Meta-w to mark and copy test regions
- CLI now uses `copy` and `rpc` tools instead of deprecated `sysrepocfg`. The
latter now also require the use of `sudo` for `admin` level users
- Enhanced `copy` command with XPath filtering support
- Kernel now announces details of new USB devices
- Add memory tuning configuration for embedded network devices with aggressive
dirty page writeback and OOM panic for deterministic recovery
### Fixes
- Fix #1082: Wi-Fi interfaces always scanned, introduce a `scan-mode` to the
Wi-Fi concept in Infix
- Fix #1314: Raspberry Pi 4B with 1 or 8 GiB RAM does not boot. This was due
newer EEPROM firmware in newer boards require a newer rpi-firmware package
- Fix #1345: firewall not updating when interfaces become bridge/lag ports
- Fix #1346: firewall complains in syslog, missing `/etc/firewalld/firewalld.conf`
- Fix default password hash in `do password encrypt` command. New hash is the
same as the more commonly used `change password` command, *yescrypt*
- Prevent MOTD from showing on non-shell user login attempts
- Fix mDNS reflector.
[wifi]: https://kernelkit.org/infix/latest/wifi/
[sd card image]: https://github.com/kernelkit/infix/releases/download/latest-boot/infix-rpi64-sdcard.img
N/A
[v25.11.0][] - 2025-12-02
-------------------------
-284
View File
@@ -1,284 +0,0 @@
# Bridging
This is the most central part of the system. A bridge is a switch, and
a switch is a bridge. In Linux, setting up a bridge with ports
connected to physical switch fabric, means you manage the actual switch
fabric!
## MAC Bridge
In Infix ports are by default not switch ports, unless the customer
specific factory config sets it up this way. To enable switching, with
offloading if you have a switch chipset, between ports you create a
bridge and then add ports to that bridge. Like this:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>up</b>
admin@example:/config/> <b>set interface eth0 bridge-port bridge br0</b>
admin@example:/config/> <b>set interface eth1 bridge-port bridge br0</b>
admin@example:/config/> <b>leave</b>
</code></pre>
Here we add two ports to bridge `br0`: `eth0` and `eth1`.
> [!TIP]
> The CLI has several built-in helpers governed by convention. E.g.,
> naming bridges `brN`, where `N` is a number, the type is *inferred*
> automatically and unlocks all bridge features. Other conventions are
> `vethNA`, where `N` is a number and `A` is a letter ('a' for access
> port and 'b' for bridge side is common), and `ethN.M` for VLAN M on
> top of `ethN`, or `dockerN` for a IP masquerading container bridge.
>
> Note, this inference only works with the CLI, configuring networking
> over NETCONF or RESTCONF requires setting the type explicitly.
![A MAC bridge with two ports](img/mac-bridge.svg)
It is possible to create multiple MAC bridges, however, it is
currently[^1] _not recommended_ to use more than one MAC bridge on
products with Marvell LinkStreet switching ASICs. A VLAN filtering
bridge should be used instead.
## VLAN Filtering Bridge
By default bridges in Linux do not filter based on VLAN tags. This can
be enabled when creating a bridge by adding a port to a VLAN as a tagged
or untagged member. Use the port default VID (PVID) setting to control
VLAN association for traffic ingressing a port untagged (default PVID:
1).
<pre class="cli"><code>admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>up</b>
admin@example:/config/> <b>set interface eth0 bridge-port bridge br0</b>
admin@example:/config/> <b>set interface eth0 bridge-port pvid 10</b>
admin@example:/config/> <b>set interface eth1 bridge-port bridge br0</b>
admin@example:/config/> <b>set interface eth1 bridge-port pvid 20</b>
admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>set bridge vlans vlan 10 untagged eth0</b>
admin@example:/config/interface/br0/> <b>set bridge vlans vlan 20 untagged eth1</b>
</code></pre>
This sets `eth0` as an untagged member of VLAN 10 and `eth1` as an
untagged member of VLAN 20. Switching between these ports is thus
prohibited.
![A VLAN bridge with two VLANs](img/vlan-bridge.svg)
To terminate a VLAN in the switch itself, either for switch management
or for routing, the bridge must become a (tagged) member of the VLAN.
<pre class="cli"><code>admin@example:/config/interface/br0/> <b>set bridge vlans vlan 10 tagged br0</b>
admin@example:/config/interface/br0/> <b>set bridge vlans vlan 20 tagged br0</b>
</code></pre>
To route or to manage via a VLAN, a VLAN interface needs to be created
on top of the bridge, see section [VLAN Interfaces](ethernet.md#vlan-interfaces)
for more on this topic.
> [!NOTE]
> In some use-cases only a single management VLAN on the bridge is used.
> For the example above, if the bridge itself is an untagged member only
> in VLAN 10, IP addresses can be set directly on the bridge without the
> need for dedicated VLAN interfaces on top of the bridge.
## Multicast Filtering and Snooping
Multicast filtering in the bridge is handled by the bridge itself. It
can filter both IP multicast and MAC multicast. For IP multicast it
also supports "snooping", i.e., IGMP and MLD, to automatically reduce
the broadcast effects of multicast. See the next section for a summary
of the [terminology used](#terminology-abbreviations).
> [!IMPORTANT]
> Currently there is no way to just enable multicast filtering without
> also enabling snooping. This may change in the future, in which case
> a `filtering` enabled setting will be made available along with the
> existing `snooping` setting.
When creating your bridge you must decide if you need a VLAN filtering
bridge or a plain bridge (see previous section). Multicast filtering is
supported for either, but take note that it must be enabled and set up
per VLAN when VLAN filtering is enabled -- there are no global multicast
settings in this operating mode.
In the following example we have a regular 8-port bridge without VLAN
filtering. We focus on the multicast specific settings:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>set bridge multicast snooping</b>
admin@example:/config/interface/br0/> <b>set ipv4 address 192.168.2.1 prefix-length 24</b>
admin@example:/config/interface/br0/> <b>leave</b>
admin@example:/> <b>copy running-config startup-config</b>
</code></pre>
Here we enable snooping and set a static IPv4 address so that the switch
can take part in IGMP querier elections. (MLD querier election
currently not supported.) We can inspect the current state:
<pre class="cli"><code>admin@example:/> <b>show ip multicast</b>
Multicast Overview
Query Interval (default): 125 sec
Router Timeout : 255
Fast Leave Ports :
Router Ports :
Flood Ports : e0, e1, e2, e3, e4, e5, e6, e7
<span class="header">Interface VID Querier State Interval Timeout Ver</span>
br0 192.168.2.1 Up 125 None 3
<span class="header">Bridge VID Multicast Group Ports </span>
br0 224.1.1.1 e3, e2
br0 ff02::6a br0
</code></pre>
This is a rather small LAN, so our bridge has already become the elected
IGMP querier. We see it is ours because the timeout is `None`, and we
recognize the IP address the system has detected, as ours. We can also
see two ports that have joined the same IPv4 multicast group, 224.1.1.1,
and one join from the system itself for the IPv6 group ff02::6a.
Now, let us see what happens when we add another bridge, this time with
VLAN filtering enabled. We skip the boring parts about how to move
ports e4-e7 to `br1` and assign them to VLANs, and again, focus on the
multicast bits only:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface br1</b>
admin@example:/config/interface/br1/> <b>set bridge vlans vlan 1 multicast snooping</b>
admin@example:/config/interface/br1/> <b>set bridge vlans vlan 2 multicast snooping</b>
admin@example:/config/interface/br1/> <b>leave</b>
admin@example:/> <b>copy running-config startup-config</b>
</code></pre>
Let us see what we get:
<pre class="cli"><code>admin@example:/> <b>show ip multicast</b>
Multicast Overview
Query Interval (default): 125 sec
Router Timeout : 255
Fast Leave Ports : e5
Router Ports : e1, e2, e5, e6, e7
Flood Ports : e1, e2, e3, e4, e5, e6, e7, e8
<span class="header">Interface VID Querier State Interval Timeout Ver</span>
br0 192.168.2.1 Up 125 None 3
br1 1 0.0.0.0 Up 125 None 3
br1 2 0.0.0.0 Up 125 None 3
<span class="header">Bridge VID Multicast Group Ports </span>
br0 224.1.1.1 e2
br0 ff02::fb br0
br0 ff02::6a br0
br0 ff02::1:ff00:0 br0
br1 1 224.1.1.1 e5
br1 2 224.1.1.1 e7
br1 1 ff02::fb br1
br1 1 ff02::1:ff00:0 br1
</code></pre>
In this setup we have a lot more going on. Multiple multicast router
ports have been detected, and behind the scenes someone has also added
an IGMP/MLD fast-leave port.
### Terminology & Abbreviations
- **IGMP**: Internet Group Membership Protocol, multicast subscription
for IPv4, for details see [RFC3376][]
- **MLD**: Multicast Listener Discovery (Protocol), multicast
subscription for IPv6, for details see [RFC3810][]
- **Unknown/Unregistered multicast**: multicast groups that are *not*
in the multicast forwarding database (MDB)
- **Known/Registered multicast**: multicast groups that *are* in the
multicast forwarding database (MDB)
- **MDB**: the multicast forwarding database, consists of filters for
multicast groups, directing where multicast is allowed to egress. A
filter entry consists of a group and a port list. The bridge filters
with a unique database per VLAN, in the same was as the unicast FDB
- **Join/Leave**: the terminology used in earlier versions of the two
protocols to subscribe and unsubscribe to a multicast group. For
more information, see *Membership Report*
- **Membership Report** A membership report is sent by end-devices and
forwarded by switches to the elected querier on the LAN. They
consist of multiple "join" and "leave" operations on groups. They
can also, per group, list which senders to allow or block. Switches
usually only support the group subscription, and even more common
also only support filtering on the MAC level[^2]
- **Querier election**: the process of determining who is the elected
IGMP/MLD querier on a LAN. Lowest numerical IP address wins, the
special address 0.0.0.0 (proxy querier) never wins
- **Proxy querier**: when no better querier exists on a LAN, one or
more devices can send proxy queries with source address 0.0.0.0 (or
:: for IPv6). See **Query Interval**, below, why this is a good
thing
- **Query interval**: the time in seconds between two queries from an
IGMP/MLD querier. It is not uncommon that end-devices do not send
their membership reports unless they first hear a query
- **Fast Leave**: set on a bridge port to ensure multicast is pruned as
quickly as possible when a "leave" membership report is received. In
effect, this option marks the port as directly connected to an
end-device. When not set (default), a query with timeout is first
sent to ensure no unintentional loss of multicast is incurred
- **Router port**: can be both configured statically and detected at
runtime based on connected devices, usually multicast routers. On
a router port *all* multicast is forwarded, both known and unknown
- **Flood port**: set on a bridge port (default: enabled) to ensure
all *unknown* multicast is forwarded
- **Router timeout**: the time in seconds until a querier is deemed to
have been lost and another device (switch/router) takes over. In the
tables shown above, a *None* timeout is declared when the current
device is the active querier
> [!TIP]
> The reason why multicast flooding is enabled by default is to ensure
> safe co-existence with MAC multicast, which is common in industrial
> networks. It also allows end devices that do not know of IGMP/MLD to
> communicate over multicast as long as the group they have chosen is
> not used by other IGMP/MLD aware devices on the LAN.
>
> As soon as an IGMP/MLD membership report to "join" a group is received
> the group is added to the kernel MDB and forwarding to other ports
> stop. The only exception to this rule is multicast router ports.
>
> If your MAC multicast forwarding is not working properly, it may be
> because an IP multicast group maps to the same MAC address. Please
> see [RFC 1112][RFC1112] for details. Use static multicast router
> ports, or static multicast MAC filters, to mitigate.
[RFC1112]: https://www.rfc-editor.org/rfc/rfc1112.html
[RFC3376]: https://www.rfc-editor.org/rfc/rfc3376.html
[RFC3810]: https://www.rfc-editor.org/rfc/rfc3810.html
## Forwarding of IEEE Reserved Group Addresses
Addresses in the range `01:80:C2:00:00:0X` are used by various bridge
signaling protocols, and are not forwarded by default. Still, it is
sometimes useful to let the bridge forward such packets, this can be
done by specifying protocol names or the last address *nibble* as
decimal value `0..15`:
<pre class="cli"><code>admin@example:/config/> <b>edit interface br0 bridge</b>
admin@example:/config/interface/br0/bridge/> <b>set ieee-group-forward</b> # Tap the ? key for alternatives
[0..15] List of IEEE link-local protocols to forward, e.g., STP, LLDP
dot1x 802.1X Port-Based Network Access Control.
lacp 802.3 Slow Protocols, e.g., LACP.
lldp 802.1AB Link Layer Discovery Protocol (LLDP).
stp Spanning Tree (STP/RSPT/MSTP).
admin@example:/config/interface/br0/bridge/> <b>set ieee-group-forward</b>
</code></pre>
The following example configures bridge *br0* to forward LLDP packets.
<pre class="cli"><code>admin@example:/config/interface/br0/bridge/> <b>set ieee-group-forward lldp</b>
admin@example:/config/interface/br0/bridge/>
</code></pre>
[^1]: MAC bridges on Marvell Linkstreet devices are currently limited to
a single MAC database, this may be a problem if the same MAC address
appears in different MAC bridges.
[^2]: For example, IPv4 groups are mapped to MAC multicast addresses by
mapping the low-order 23-bits of the IP address in the low-order 23
bits of the Ethernet address 01:00:5E:00:00:00. Meaning, more than
one IP multicast group maps to the same MAC multicast group.
+1 -6
View File
@@ -16,21 +16,16 @@ CLI has several keybindings, most significant first:
| Meta-b | Ctrl-Left | Move cursor back one word |
| Ctrl-e | End | Move cursor to end of line |
| Ctrl-a | Home | Move cursor to beginning of line |
| Ctrl-@ | Ctrl-Space | Mark current position for region operations |
| Meta w | | Copy region to kill buffer without deleting |
| Ctrl-k | | Kill (cut) text from cursor to end of line |
| Ctrl-u | | Delete (cut) entire line |
| Ctrl-y | | Yank (paste) from kill buffer to cursor |
| Meta-. | | Yank (paste) last argument from previous line |
| Ctrl-w | | Kill region if mark set, else kill word backward |
| | Meta-Backspace | Delete (cut) word to the left |
| Ctrl-w | Meta-Backspace | Delete (cut) word to the left |
| | Meta-Delete | Delete (cut) word to the right |
| Ctrl-l | | Clear screen and refresh current line |
| Ctrl-p | Up arrow | History, previous command |
| Ctrl-n | Down arrow | History, next command |
| Ctrl-q | Ctrl-v | Insert next character literally |
| Ctrl-r | | History, reversed interactive search (i-search) |
| Ctrl-t | | Transpose/Swap characters before and at cursor |
## What is Meta?
+242 -311
View File
@@ -92,18 +92,17 @@ your container image and application to run.
Classic Hello World:
<pre class="cli"><code>admin@example:/> <b>container run docker://hello-world</b>
Starting docker://hello-world :: use Ctrl-p Ctrl-q to detach
Trying to pull docker.io/library/hello-world:latest...
Getting image source signatures
Copying blob c1ec31eb5944 done
Copying config d2c94e258d done
Writing manifest to image destination
Storing signatures
admin@example:/> container run docker://hello-world
Starting docker://hello-world :: use Ctrl-p Ctrl-q to detach
Trying to pull docker.io/library/hello-world:latest...
Getting image source signatures
Copying blob c1ec31eb5944 done
Copying config d2c94e258d done
Writing manifest to image destination
Storing signatures
Hello from Docker!
This message shows that your installation appears to be working correctly.
</code></pre>
Hello from Docker!
This message shows that your installation appears to be working correctly.
### Example: Web Server
@@ -111,24 +110,22 @@ A web server with [nginx][], using standard docker bridge. Podman will
automatically create a VETH pair for us, connecting the container to the
`docker0` bridge:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface docker0</b>
admin@example:/config/interface/docker0/> <b>set container-network</b>
admin@example:/config/interface/docker0/> <b>end</b>
admin@example:/config/> <b>edit container web</b>
admin@example:/config/container/web/> <b>set image docker://nginx:alpine</b>
admin@example:/config/container/web/> <b>set network publish 8080:80</b>
admin@example:/config/container/web/> <b>set network interface docker0</b>
admin@example:/config/container/web/> <b>set volume cache target /var/cache</b>
admin@example:/config/container/web/> <b>leave</b>
admin@example:/> <b>show container</b>
</code></pre>
admin@example:/> configure
admin@example:/config/> edit interface docker0
admin@example:/config/interface/docker0/> set container-network
admin@example:/config/interface/docker0/> end
admin@example:/config/> edit container web
admin@example:/config/container/web/> set image docker://nginx:alpine
admin@example:/config/container/web/> set network publish 8080:80
admin@example:/config/container/web/> set network interface docker0
admin@example:/config/container/web/> set volume cache target /var/cache
admin@example:/config/container/web/> leave
admin@example:/> show container
Exit to the shell and verify the service with curl, or try to attach
to your device's IP address using your browser:
<pre class="cli"><code>admin@example:~$ <b>curl http://localhost:8080</b>
</code></pre>
admin@example:~$ curl http://localhost:8080
or connect to port 8080 of your running Infix system with a browser.
See the following sections for how to add more interfaces and manage
@@ -145,32 +142,31 @@ how to upgrade to a newer base image.
The CLI help shows:
<pre class="cli"><code>admin@example:/config/container/system/> <b>help image</b>
<b>NAME</b>
image &lt;string&gt;
admin@example:/config/container/system/> help image
NAME
image <string>
<b>DESCRIPTION</b>
Docker image for the container: [transport]name[:tag|@digest]
DESCRIPTION
Docker image for the container: [transport]name[:tag|@digest]
quay.io/username/myimage -- Pull myimage:latest
docker://busybox -- Pull busybox:latest from Docker Hub
docker://ghcr.io/usr/img -- Pull img:latest from GitHub packages
dir:/media/usb/myimage:1.1 -- Use myimage v1.1 from USB media
docker-archive:/tmp/archive -- Use archive:latest from tarball
oci-archive:/lib/oci/archive -- Use archive:latest from OCI archive
May be in .tar or .tar.gz format
quay.io/username/myimage -- Pull myimage:latest
docker://busybox -- Pull busybox:latest from Docker Hub
docker://ghcr.io/usr/img -- Pull img:latest from GitHub packages
dir:/media/usb/myimage:1.1 -- Use myimage v1.1 from USB media
docker-archive:/tmp/archive -- Use archive:latest from tarball
oci-archive:/lib/oci/archive -- Use archive:latest from OCI archive
May be in .tar or .tar.gz format
Additionally, the following URIs are also supported for setups
that do not use a HUB or similar. Recommend using 'checksum'!
Additionally, the following URIs are also supported for setups
that do not use a HUB or similar. Recommend using 'checksum'!
ftp://addr/path/to/archive -- Downloaded using wget
http://addr/path/to/archive -- Downloaded using curl
https://addr/path/to/archive -- Downloaded using curl
ftp://addr/path/to/archive -- Downloaded using wget
http://addr/path/to/archive -- Downloaded using curl
https://addr/path/to/archive -- Downloaded using curl
Note: if a remote repository cannot be reached, the creation of the
container will be put on a queue that retries pull every time
there is a route change in the host's system.
</code></pre>
Note: if a remote repository cannot be reached, the creation of the
container will be put on a queue that retries pull every time
there is a route change in the host's system.
> [!TIP]
> The built-in help system in the CLI is generated from the YANG model,
@@ -202,28 +198,26 @@ mind.
**Shell OCI Example:**
<pre class="cli"><code>admin@example:~$ <b>cd /var/tmp/</b>
admin@example:/var/tmp$ <b>sudo wget https://github.com/kernelkit/curiOS/releases/download/edge/curios-oci-amd64.tar.gz</b>
Connecting to github.com (140.82.121.3:443)
wget: note: TLS certificate validation not implemented
Connecting to objects.githubusercontent.com (185.199.109.133:443)
saving to 'curios-oci-amd64.tar.gz'
curios-oci-amd64.tar 100% |*********************************| 7091k 0:00:00 ETA
'curios-oci-amd64.tar.gz' saved
admin@example:/var/tmp$ <b>ll</b>
total 7104
drwxr-xr-x 3 root root 4096 Mar 27 14:22 ./
drwxr-xr-x 14 root root 4096 Mar 27 11:57 ../
-rw-r--r-- 1 root root 7261785 Mar 27 14:22 curios-oci-amd64.tar.gz
drwx------ 6 frr frr 4096 Mar 27 11:57 frr/
</code></pre>
admin@example:~$ cd /var/tmp/
admin@example:/var/tmp$ sudo wget https://github.com/kernelkit/curiOS/releases/download/edge/curios-oci-amd64.tar.gz
Connecting to github.com (140.82.121.3:443)
wget: note: TLS certificate validation not implemented
Connecting to objects.githubusercontent.com (185.199.109.133:443)
saving to 'curios-oci-amd64.tar.gz'
curios-oci-amd64.tar 100% |*********************************| 7091k 0:00:00 ETA
'curios-oci-amd64.tar.gz' saved
admin@example:/var/tmp$ ll
total 7104
drwxr-xr-x 3 root root 4096 Mar 27 14:22 ./
drwxr-xr-x 14 root root 4096 Mar 27 11:57 ../
-rw-r--r-- 1 root root 7261785 Mar 27 14:22 curios-oci-amd64.tar.gz
drwx------ 6 frr frr 4096 Mar 27 11:57 frr/
Importing the image into Podman can be done either from the CLI
admin-exec context ...
<pre class="cli"><code>admin@example:/var/tmp$ <b>cli</b>
admin@example:/> <b>container load /var/tmp/curios-oci-amd64.tar.gz name curios:edge</b>
</code></pre>
admin@example:/var/tmp$ cli
admin@example:/> container load /var/tmp/curios-oci-amd64.tar.gz name curios:edge
> [!TIP]
> The `name curios:edge` is the tag you give the imported (raw) archive
@@ -233,33 +227,31 @@ admin@example:/> <b>container load /var/tmp/curios-oci-amd64.tar.gz name curios:
... or by giving the container configuration the full path to the OCI
archive, which helps greatly with container upgrades (see below):
<pre class="cli"><code>admin@example:/config/container/system/> <b>set image oci-archive:/var/tmp/curios-oci-amd64.tar.gz</b>
</code></pre>
admin@example:/config/container/system/> set image oci-archive:/var/tmp/curios-oci-amd64.tar.gz
**Checksum Example:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit container sys</b>
admin@example:/config/container/sys/> <b>set hostname sys</b>
admin@example:/config/container/sys/> <b>set image ftp://192.168.122.1/curios-oci-amd64-v24.05.0.tar.gz</b>
admin@example:/config/container/sys/> <b>set checksum</b>
md5 sha256 sha512
admin@example:/config/container/sys/> <b>set checksum sha256 4f01077036527498ed910f1a3e80645ae3eff629d10043cf80ebc6850c99c629</b>
admin@example:/config/container/sys/> <b>leave</b>
admin@example:/> <b>copy running-config startup-config</b>
admin@example:/> <b>show container</b>
<span class="header">NAME STATUS NETWORK MEMORY (KiB) CPU%</span>
sys Up 5 seconds 72/512 0.02
admin@example:/> configure
admin@example:/config/> edit container sys
admin@example:/config/container/sys/> set hostname sys
admin@example:/config/container/sys/> set image ftp://192.168.122.1/curios-oci-amd64-v24.05.0.tar.gz
admin@example:/config/container/sys/> set checksum
md5 sha256 sha512
admin@example:/config/container/sys/> set checksum sha256 4f01077036527498ed910f1a3e80645ae3eff629d10043cf80ebc6850c99c629
admin@example:/config/container/sys/> leave
admin@example:/> copy running-config startup-config
admin@example:/> show container
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b02e945c43c9 localhost/curios-oci-amd64-v24.05.0:latest 5 seconds ago Up 5 seconds sys
admin@example:/> <b>show log</b>
...
Nov 20 07:24:56 example container[5040]: Fetching ftp://192.168.122.1/curios-oci-amd64-v24.05.0.tar.gz
Nov 20 07:24:56 example container[5040]: curios-oci-amd64-v24.05.0.tar.gz downloaded successfully.
Nov 20 07:24:56 example container[5040]: curios-oci-amd64-v24.05.0.tar.gz checksum verified OK.
Nov 20 07:24:57 example container[5040]: Cleaning up extracted curios-oci-amd64-v24.05.0
Nov 20 07:24:57 example container[5040]: podman create --name sys --conmon-pidfile=/run/container:sys.pid --read-only --replace --quiet --cgroup-parent=containers --restart=always --systemd=false --tz=local --hostname sys --log-driver k8s-file --log-opt path=/run/containers/sys.fifo --network=none curios-oci-amd64-v24.05.0
Nov 20 07:24:57 example container[3556]: b02e945c43c9bce2c4be88e31d6f63cfdb1a3c8bdd02179376eb059a49ae05e4
</code></pre>
admin@example:/> show log
...
Nov 20 07:24:56 example container[5040]: Fetching ftp://192.168.122.1/curios-oci-amd64-v24.05.0.tar.gz
Nov 20 07:24:56 example container[5040]: curios-oci-amd64-v24.05.0.tar.gz downloaded successfully.
Nov 20 07:24:56 example container[5040]: curios-oci-amd64-v24.05.0.tar.gz checksum verified OK.
Nov 20 07:24:57 example container[5040]: Cleaning up extracted curios-oci-amd64-v24.05.0
Nov 20 07:24:57 example container[5040]: podman create --name sys --conmon-pidfile=/run/container:sys.pid --read-only --replace --quiet --cgroup-parent=containers --restart=always --systemd=false --tz=local --hostname sys --log-driver k8s-file --log-opt path=/run/containers/sys.fifo --network=none curios-oci-amd64-v24.05.0
Nov 20 07:24:57 example container[3556]: b02e945c43c9bce2c4be88e31d6f63cfdb1a3c8bdd02179376eb059a49ae05e4
Understanding Image Tags
@@ -367,11 +359,12 @@ writable paths provided by Podman (`/dev`, `/dev/shm`, `/run`, `/tmp`,
When using version-specific tags, you upgrade by explicitly changing the
image reference in your configuration:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit container web</b>
admin@example:/config/container/web/> <b>set image docker://nginx:1.25.3</b>
admin@example:/config/container/web/> <b>leave</b>
</code></pre>
```
admin@example:/> configure
admin@example:/config/> edit container web
admin@example:/config/container/web/> set image docker://nginx:1.25.3
admin@example:/config/container/web/> leave
```
**What happens:**
@@ -382,27 +375,29 @@ admin@example:/config/container/web/> <b>leave</b>
**Example:** Upgrading from one version to another:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit container system</b>
admin@example:/config/container/system/> <b>show image</b>
```
admin@example:/> configure
admin@example:/config/> edit container system
admin@example:/config/container/system/> show image
image ghcr.io/kernelkit/curios:v24.11.0;
admin@example:/config/container/system/> <b>set image ghcr.io/kernelkit/curios:v24.12.0</b>
admin@example:/config/container/system/> <b>leave</b>
admin@example:/> <b>show log</b>
admin@example:/config/container/system/> set image ghcr.io/kernelkit/curios:v24.12.0
admin@example:/config/container/system/> leave
admin@example:/> show log
...
Dec 13 14:32:15 example container[1523]: Pulling ghcr.io/kernelkit/curios:v24.12.0...
Dec 13 14:32:18 example container[1523]: Stopping old container instance...
Dec 13 14:32:19 example container[1523]: Creating new container with updated image...
Dec 13 14:32:20 example container[1523]: Container system started successfully
</code></pre>
```
### Method 2: Upgrading Mutable Tags
For images using mutable tags like `:latest` or `:edge`, use the
`container upgrade` command:
<pre class="cli"><code>admin@example:/> <b>container upgrade NAME</b>
</code></pre>
```
admin@example:/> container upgrade NAME
```
This command:
@@ -413,7 +408,8 @@ This command:
**Example using registry:**
<pre class="cli"><code>admin@example:/> <b>container upgrade system</b>
```
admin@example:/> container upgrade system
system
Trying to pull ghcr.io/kernelkit/curios:edge...
Getting image source signatures
@@ -424,7 +420,7 @@ Storing signatures
0cb6059c0f4111650ddbc7dbc4880c64ab8180d4bdbb7269c08034defc348f17
system: not running.
59618cc3c84bef341c1f5251a62be1592e459cc990f0b8864bc0f5be70e60719
</code></pre>
```
**Example using local OCI archive:**
@@ -433,10 +429,11 @@ new archive onto the system (see Container Images section above), then,
provided the `oci-archive:/path/to/archive` format is used in your
configuration, call the upgrade command:
<pre class="cli"><code>admin@example:/> <b>container upgrade system</b>
```
admin@example:/> container upgrade system
Upgrading container system with local archive: oci-archive:/var/tmp/curios-oci-amd64.tar.gz ...
7ab4a07ee0c6039837419b7afda4da1527a70f0c60c0f0ac21cafee05ba24b52
</code></pre>
```
OCI archives can also be fetched from ftp/http/https URLs. In that case,
the upgrade works the same way as a registry image — Infix downloads the
@@ -475,16 +472,15 @@ occasions where they are too restricted and users start looking for the
For example, a system container from which `ping` does not work:
<pre class="cli"><code>admin@example:/config/container/system/> <b>edit capabilities</b>
admin@example:/config/container/system/capabilities/> <b>set add net_raw</b>
admin@example:/config/container/system/capabilities/> <b>end</b>
admin@infix-00-00-00:/config/container/system/> <b>show</b>
...
capabilities {
add net_raw;
}
...
</code></pre>
admin@example:/config/container/system/> edit capabilities
admin@example:/config/container/system/capabilities/> set add net_raw
admin@example:/config/container/system/capabilities/> end
admin@infix-00-00-00:/config/container/system/> show
...
capabilities {
add net_raw;
}
...
Infix supports a subset of all [capabilities][6] that are relevant for
containers. Please note, that this is an advanced topic that require
@@ -492,48 +488,6 @@ time and analysis of your container application to figure out which
capabilities you need.
Resource Limits
---------------
Containers can be configured with resource limits to control their memory
and CPU usage. This helps prevent containers from consuming excessive system
resources and ensures fair resource allocation across multiple containers.
### Configuring Resource Limits
Resource limits are set per container and include:
- **Memory:** Maximum memory usage in kibibytes (KiB)
- **CPU:** Maximum CPU usage in millicores (1000 millicores = 1 CPU core)
Example configuration limiting a container to 512 MiB of memory and 1.5 CPU cores:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit container web</b>
admin@example:/config/container/web/> <b>edit resource-limit</b>
admin@example:/config/container/web/resource-limit/> <b>set memory 524288</b>
admin@example:/config/container/web/resource-limit/> <b>set cpu 1500</b>
admin@example:/config/container/web/resource-limit/> <b>leave</b>
</code></pre>
Common CPU limit examples:
- `500` = 0.5 cores (50% of one core)
- `1000` = 1.0 cores (one full core)
- `2000` = 2.0 cores (two full cores)
### Monitoring Resource Usage
Runtime resource usage statistics are available in the operational datastore:
<pre class="cli"><code>admin@example:/> <b>show container web</b>
...
</code></pre>
Use `show container usage` to see resource consumption across all containers,
including memory, CPU, block I/O, network I/O, and process counts.
Networking and Containers
-------------------------
@@ -569,11 +523,10 @@ container use seem to be so simple.
All interface configuration is done in configure context.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config> <b>edit interface docker0</b>
admin@example:/config/interface/docker0/> <b>set container-network</b>
admin@example:/config/interface/docker0/> <b>leave</b>
</code></pre>
admin@example:/> configure
admin@example:/config> edit interface docker0
admin@example:/config/interface/docker0/> set container-network
admin@example:/config/interface/docker0/> leave
There is more to this story. When using the CLI, and sticking to common
interface nomenclature, Infix helps you with some of the boring stuff.
@@ -581,9 +534,8 @@ E.g., creating a new interface with a name like `brN` or `dockerN`
automatically *infers* the interface types, which you would otherwise
have to set manually:
<pre class="cli"><code>admin@example:/config/interface/docker0/> <b>set type bridge</b>
admin@example:/config/interface/docker0/> <b>set container-network type bridge</b>
</code></pre>
admin@example:/config/interface/docker0/> set type bridge
admin@example:/config/interface/docker0/> set container-network type bridge
> [!IMPORTANT]
> When configuring the system via an API such as NETCONF or RESTCONF, no
@@ -609,17 +561,16 @@ other networking parameters (DNS, default route) are set up.
Some of the defaults of a container `bridge` can be changed, e.g.,
instead of `set container-network type bridge`, above, do:
<pre class="cli"><code>admin@example:/config/interface/docker0/> <b>edit container-network</b>
admin@example:/config//container-network/> <b>set type bridge</b>
admin@example:/config//container-network/> <b>edit subnet 192.168.0.0/16</b>
admin@example:/config//subnet/192.168.0.0/16/> <b>set gateway 192.168.255.254</b>
admin@example:/config//subnet/192.168.0.0/16/> <b>end</b>
admin@example:/config//container-network/> <b>edit route 10.0.10.0/24</b>
admin@example:/config//route/10.0.10.0/24/> <b>set gateway 192.168.10.254</b>
admin@example:/config//route/10.0.10.0/24/> <b>end</b>
admin@example:/config//container-network/> <b>end</b>
admin@example:/config/interface/docker0/> <b>leave</b>
</code></pre>
admin@example:/config/interface/docker0/> edit container-network
admin@example:/config/interface/docker0/container-network/> set type bridge
admin@example:/config/interface/docker0/container-network/> edit subnet 192.168.0.0/16
admin@example:/config/interface/docker0/container-network/subnet/192.168.0.0/16/> set gateway 192.168.255.254
admin@example:/config/interface/docker0/container-network/subnet/192.168.0.0/16/> end
admin@example:/config/interface/docker0/container-network/> edit route 10.0.10.0/24
admin@example:/config/interface/docker0/container-network/route/10.0.10.0/24/> set gateway 192.168.10.254
admin@example:/config/interface/docker0/container-network/route/10.0.10.0/24/> end
admin@example:/config/interface/docker0/container-network/> end
admin@example:/config/interface/docker0/> leave
Other network settings, like DNS and domain, use built-in defaults, but
can be overridden from each container. Other common settings per
@@ -631,25 +582,24 @@ in a `bridge`. Below an example of a system container calls `set
network interface docker0`, here we show how to set options for that
network:
<pre class="cli"><code>admin@example:/config/container/ntpd/> <b>edit network interface docker0</b>
admin@example:/config//network/interface/docker0/>
admin@example:/config//network/interface/docker0/> <b>set option</b>
&lt;string&gt; Options for masquerading container bridges.
admin@example:/config//network/interface/docker0/> <b>help option</b>
NAME
option &lt;string&gt;
admin@example:/config/container/ntpd/> edit network interface docker0
admin@example:/config/container/ntpd/network/interface/docker0/>
admin@example:/config/container/ntpd/network/interface/docker0/> set option
<string> Options for masquerading container bridges.
admin@example:/config/container/ntpd/network/interface/docker0/> help option
NAME
option <string>
DESCRIPTION
Options for masquerading container bridges.
DESCRIPTION
Options for masquerading container bridges.
Example: ip=1.2.3.4 -- request a specific IP (IPv4 or IPv6)
mac=00:01:02:c0:ff:ee -- set fixed MAC address in container
interface_name=foo0 -- set interface name inside container
admin@example:/config/…/network/interface/docker0/> <b>set option ip=172.17.0.2</b>
admin@example:/config/…/network/interface/docker0/> <b>set option interface_name=wan</b>
admin@example:/config/…/network/interface/docker0/> <b>leave</b>
</code></pre>
Example: ip=1.2.3.4 -- request a specific IP (IPv4 or IPv6)
mac=00:01:02:c0:ff:ee -- set fixed MAC address in container
interface_name=foo0 -- set interface name inside container
admin@example:/config/container/ntpd/network/interface/docker0/> set option ip=172.17.0.2
admin@example:/config/container/ntpd/network/interface/docker0/> set option interface_name=wan
admin@example:/config/container/ntpd/network/interface/docker0/> leave
### Container Host Interface
@@ -684,15 +634,14 @@ container-end of pair `ntpd`. This is just a convenience for us when
reading the configuration later. The *real action* happens on the last
line where we declare the `ntpd` end as a container network interface:
<pre class="cli"><code>admin@example:/config/> <b>edit interface veth0</b>
admin@example:/config/interface/veth0/> <b>set veth peer ntpd</b>
admin@example:/config/interface/veth0/> <b>set ipv4 address 192.168.0.1 prefix-length 24</b>
admin@example:/config/interface/veth0/> <b>end</b>
admin@example:/config/> <b>edit interface ntpd</b>
admin@example:/config/interface/ntpd/> <b>set ipv4 address 192.168.0.2 prefix-length 24</b>
admin@example:/config/interface/ntpd/> <b>set custom-phys-address static 00:c0:ff:ee:00:01</b>
admin@example:/config/interface/ntpd/> <b>set container-network</b>
</code></pre>
admin@example:/config/> edit interface veth0
admin@example:/config/interface/veth0/> set veth peer ntpd
admin@example:/config/interface/veth0/> set ipv4 address 192.168.0.1 prefix-length 24
admin@example:/config/interface/veth0/> end
admin@example:/config/> edit interface ntpd
admin@example:/config/interface/ntpd/> set ipv4 address 192.168.0.2 prefix-length 24
admin@example:/config/interface/ntpd/> set custom-phys-address static 00:c0:ff:ee:00:01
admin@example:/config/interface/ntpd/> set container-network
> [!TIP]
> Notice how you can also set a custom MAC address at the same time.
@@ -701,9 +650,8 @@ Adding the interface to the container is the same as before, but since
everything for host interfaces is set up in the interfaces context, we
can take a bit of a shortcut.
<pre class="cli"><code>admin@example:/config/container/ntpd/> <b>set network interface ntpd</b>
admin@example:/config/container/ntpd/> <b>leave</b>
</code></pre>
admin@example:/config/container/ntpd/> set network interface ntpd
admin@example:/config/container/ntpd/> leave
> [!TIP]
> Use the `set network interface ntpd option interface_name=foo0` to set
@@ -724,10 +672,9 @@ pair to give our container two interfaces:
We start by adding the second VETH pair:
<pre class="cli"><code>admin@example:/config/> <b>edit interface veth1a</b>
admin@example:/config/interface/veth1a/> <b>set veth peer veth1</b>
admin@example:/config/interface/veth1a/> <b>set ipv4 address 192.168.1.2 prefix-length 24</b>
</code></pre>
admin@example:/config/> edit interface veth1a
admin@example:/config/interface/veth1a/> set veth peer veth1
admin@example:/config/interface/veth1a/> set ipv4 address 192.168.1.2 prefix-length 24
> [!NOTE]
> The LAN bridge (br1) in this example has IP address 192.168.1.1.
@@ -736,21 +683,20 @@ When a container has multiple host interfaces it can often be useful to
have a default route installed. This can be added from the host with a
`0.0.0.0/0` route on one of the interfaces:
<pre class="cli"><code>admin@example:/config/interface/veth1a/> <b>set container-network route 0.0.0.0/0 gateway 192.168.1.1</b>
admin@example:/config/interface/veth1a/> <b>show</b>
type veth;
container-network {
type host;
route 0.0.0.0/0 {
gateway 192.168.1.1;
}
}
veth {
peer veth1;
}
admin@example:/config/interface/veth1a/> <b>end</b>
admin@example:/config/> <b>set interface veth1 bridge-port bridge br1</b>
</code></pre>
admin@example:/config/interface/veth1a/> set container-network route 0.0.0.0/0 gateway 192.168.1.1
admin@example:/config/interface/veth1a/> show
type veth;
container-network {
type host;
route 0.0.0.0/0 {
gateway 192.168.1.1;
}
}
veth {
peer veth1;
}
admin@example:/config/interface/veth1a/> end
admin@example:/config/> set interface veth1 bridge-port bridge br1
Please note, container network routes require the base interface also
have a static IP address set. Setting only the route, but no address,
@@ -776,12 +722,11 @@ It is possible to mount files, directories, and even files matching a
glob, into a container. This gives precise control over the container's
file system:
<pre class="cli"><code>admin@example:/config/container/system/> <b>edit mount leds</b>
admin@example:/config/container/system/mount/leds> <b>set source /sys/class/leds</b>
admin@example:/config/container/system/mount/leds> <b>set target /sys/class/leds</b>
admin@example:/config/container/system/mount/leds> <b>end</b>
admin@example:/config/container/system/>
</code></pre>
admin@example:/config/container/system/> edit mount leds
admin@example:/config/container/system/mount/leds> set source /sys/class/leds
admin@example:/config/container/system/mount/leds> set target /sys/class/leds
admin@example:/config/container/system/mount/leds> end
admin@example:/config/container/system/>
Any type of file can be *bind mounted* into the container, just watch
out for permissions though. In the example above, `/sys/class/leds` is
@@ -797,8 +742,7 @@ trigger a container restart.
Other times *volumes* are a better fit. A volume is an automatically
created read-writable entity that follows the life of your container.
<pre class="cli"><code>admin@example:/config/container/ntpd/> <b>set volume varlib target /var/lib</b>
</code></pre>
admin@example:/config/container/ntpd/> set volume varlib target /var/lib
Volumes are persistent across both reboots and upgrades of the base
image. They are created by Podman when the container first starts up,
@@ -828,15 +772,14 @@ where:
To clean up unused volumes and reclaim disk space, use the admin-exec
command:
<pre class="cli"><code>admin@example:/> <b>container prune</b>
Deleted Images
...
Deleted Volumes
ntpd-varlib
system-data
admin@example:/> container prune
Deleted Images
...
Deleted Volumes
ntpd-varlib
system-data
Total reclaimed space: 45.2MB
</code></pre>
Total reclaimed space: 45.2MB
The `container prune` command safely removes:
@@ -847,16 +790,14 @@ The `container prune` command safely removes:
> [!TIP]
> You can monitor container resource usage with the command:
>
> <pre class="cli"><code>admin@example:/> <b>show container usage</b>
> </code></pre>
> admin@example:/> show container usage
>
> This displays disk space used by images, containers, and volumes,
> helping you decide when to run the prune command.
>
> To see which volumes exist and which containers use them:
>
> <pre class="cli"><code>admin@example:/> <b>show container volumes</b>
> </code></pre>
> admin@example:/> show container volumes
### Content Mounts
@@ -866,13 +807,12 @@ when deploying similar systems at multiple sites. When the host loads
its `startup-config` (or even `factory-config`) a temporary file is
created using the decoded base64 data from the `content` node.
<pre class="cli"><code>admin@example:/config/container/ntpd/> <b>edit mount ntpd.conf</b>
admin@example:/config/container/ntpd/mount/ntpd.conf> <b>text-editor content</b>
... interactive editor starts up ...
admin@example:/config/container/ntpd/mount/ntpd.conf> <b>set target /etc/ntpd.conf</b>
admin@example:/config/container/ntpd/mount/ntpd.conf> <b>end</b>
admin@example:/config/container/ntpd/>
</code></pre>
admin@example:/config/container/ntpd/> edit mount ntpd.conf
admin@example:/config/container/ntpd/mount/ntpd.conf> text-editor content
... interactive editor starts up ...
admin@example:/config/container/ntpd/mount/ntpd.conf> set target /etc/ntpd.conf
admin@example:/config/container/ntpd/mount/ntpd.conf> end
admin@example:/config/container/ntpd/>
The editor is a small [Emacs clone called Mg][2], see the built-in help
text, or press Ctrl-x Ctrl-c to exit and save. When the editor exits
@@ -896,13 +836,12 @@ Let's try out what we've learned by setting up a system container, a
container providing multiple services, using the `docker0` interface
we created previously:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config> <b>edit container system</b>
admin@example:/config/container/system/> <b>set image ghcr.io/kernelkit/curios:edge</b>
admin@example:/config/container/system/> <b>set network interface docker0</b>
admin@example:/config/container/system/> <b>set publish 222:22</b>
admin@example:/config/container/system/> <b>leave</b>
</code></pre>
admin@example:/> configure
admin@example:/config> edit container system
admin@example:/config/container/system/> set image ghcr.io/kernelkit/curios:edge
admin@example:/config/container/system/> set network interface docker0
admin@example:/config/container/system/> set publish 222:22
admin@example:/config/container/system/> leave
> [!NOTE]
> Ensure you have a network connection to the registry. If the image
@@ -917,29 +856,26 @@ container configuration context for the full syntax.)
Available containers can be accessed from admin-exec:
<pre class="cli"><code>admin@example:/> <b>show container</b>
<span class="header">NAME STATUS NETWORK MEMORY (KiB) CPU%</span>
system Up 16 hours docker0 136/512 0.02
</code></pre>
admin@example:/> show container
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
439af2917b44 ghcr.io/kernelkit/curios:edge 41 hours ago Up 16 hours 0.0.0.0:222->222/tcp system
This is a system container, so you can "attach" to it by starting a
shell (or logging in with SSH):
<pre class="cli"><code>admin@example:/> <b>container shell system</b>
root@439af2917b44:/#
</code></pre>
admin@example:/> container shell system
root@439af2917b44:/#
Notice how the hostname inside the container changes. By default the
container ID (hash) is used, but this can be easily changed:
<pre class="cli"><code>root@439af2917b44:/# <b>exit</b>
admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit container system</b>
admin@example:/config/container/system/> <b>set hostname sys101</b>
admin@example:/config/container/system/> <b>leave</b>
admin@example:/> <b>container shell system</b>
root@sys101:/#
</code></pre>
root@439af2917b44:/# exit
admin@example:/> configure
admin@example:/config/> edit container system
admin@example:/config/container/system/> set hostname sys101
admin@example:/config/container/system/> leave
admin@example:/> container shell system
root@sys101:/#
In fact, the container `hostname` setting supports the same format
specifiers as the host's `hostname` setting:
@@ -964,17 +900,16 @@ Infix currently does not have a native firewall configuration, and even
when it does it will never expose the full capabilities of `nftables`.
For advanced setups, the following is an interesting alternative.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config> <b>edit container nftables</b>
admin@example:/config/container/nftables/> <b>set image ghcr.io/kernelkit/curios-nftables:edge</b>
admin@example:/config/container/nftables/> <b>set network host</b>
admin@example:/config/container/nftables/> <b>set privileged</b>
admin@example:/config/container/nftables/> <b>edit mount nftables.conf</b>
admin@example:/config//mount/nftables.conf/> <b>set target /etc/nftables.conf</b>
admin@example:/config//mount/nftables.conf/> <b>text-editor content</b>
... interactive editor starts up where you can paste your rules ...
admin@example:/config//mount/nftables.conf/> <b>leave</b>
</code></pre>
admin@example:/> configure
admin@example:/config> edit container nftables
admin@example:/config/container/nftables/> set image ghcr.io/kernelkit/curios-nftables:edge
admin@example:/config/container/nftables/> set network host
admin@example:/config/container/nftables/> set privileged
admin@example:/config/container/nftables/> edit mount nftables.conf
admin@example:/config/container/nftables/mount/nftables.conf/> set target /etc/nftables.conf
admin@example:/config/container/nftables/mount/nftables.conf/> text-editor content
... interactive editor starts up where you can paste your rules ...
admin@example:/config/container/nftables/mount/nftables.conf/> leave
Notice how we `set network host`, so the container can see and act on
all the host's interfaces, and that we also have to run the container
@@ -993,20 +928,19 @@ file system and store in the host's `startup-config`. However, `ntpd`
also saves clock drift information in `/var/lib/ntpd`, so we will also
use volumes in this example.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config> <b>edit container ntpd</b>
admin@example:/config/container/ntpd/> <b>set image ghcr.io/kernelkit/curios-ntpd:edge</b>
admin@example:/config/container/ntpd/> <b>set network interface ntpd</b> # From veth0 above
admin@example:/config/container/ntpd/> <b>edit mount ntp.conf</b>
admin@example:/config/container/ntpd/mount/ntp.conf/> <b>set target /etc/ntp.conf</b>
admin@example:/config/container/ntpd/mount/ntp.conf/> <b>text-editor content</b>
... interactive editor starts up where you can paste your rules ...
admin@example:/config/container/ntpd/mount/ntp.conf/> <b>end</b>
admin@example:/config/container/ntpd/> <b>edit volume varlib</b>
admin@example:/config/container/ntpd/volume/varlib/> <b>set target /var/lib</b>
admin@example:/config/container/ntpd/volume/varlib/> <b>leave</b>
admin@example:/> <b>copy running-config startup-config</b>
</code></pre>
admin@example:/> configure
admin@example:/config> edit container ntpd
admin@example:/config/container/ntpd/> set image ghcr.io/kernelkit/curios-ntpd:edge
admin@example:/config/container/ntpd/> set network interface ntpd # From veth0 above
admin@example:/config/container/ntpd/> edit mount ntp.conf
admin@example:/config/container/ntpd/mount/ntp.conf/> set target /etc/ntp.conf
admin@example:/config/container/ntpd/mount/ntp.conf/> text-editor content
... interactive editor starts up where you can paste your rules ...
admin@example:/config/container/ntpd/mount/ntp.conf/> end
admin@example:/config/container/ntpd/> edit volume varlib
admin@example:/config/container/ntpd/volume/varlib/> set target /var/lib
admin@example:/config/container/ntpd/volume/varlib/> leave
admin@example:/> copy running-config startup-config
The `ntp.conf` file is stored in the host's `startup-config` and any
state data in the container's `/var/lib` is retained between reboots
@@ -1041,28 +975,25 @@ First, enable *Privileged* mode, this unlocks the door and allows the
container to manage resources on the host system. An example is the
`nftables` container mentioned previously.
<pre class="cli"><code>admin@example:/config/container/system/> <b>set privileged</b>
</code></pre>
admin@example:/config/container/system/> set privileged
Second, mount the host's `/proc/1` directory to somewhere inside your
container. Here we pick `/1`:
<pre class="cli"><code>admin@example:/config/container/system/> <b>edit mount host</b>
admin@example:/config/container/system/mount/host/> <b>set source /proc/1</b>
admin@example:/config/container/system/mount/host/> <b>set target /1</b>
admin@example:/config/container/system/mount/host/> <b>leave</b>
</code></pre>
admin@example:/config/container/system/> edit mount host
admin@example:/config/container/system/mount/host/> set source /proc/1
admin@example:/config/container/system/mount/host/> set target /1
admin@example:/config/container/system/mount/host/> leave
Third, from inside the container, use the host's PID 1 namespaces with
the `nsenter`[^2] command to slide through the container's walls. Here
we show two example calls to `hostname`, first the container's own name
and then asking what the hostname is on the host:
<pre class="cli"><code>root@sys101:/# <b>hostname</b>
sys101
root@sys101:/# <b>nsenter -m/1/ns/mnt -u/1/ns/uts -i/1/ns/ipc -n/1/ns/net hostname</b>
example
</code></pre>
root@sys101:/# hostname
sys101
root@sys101:/# nsenter -m/1/ns/mnt -u/1/ns/uts -i/1/ns/ipc -n/1/ns/net hostname
example
One use-case for this method is when extending Infix with a management
container that connects to other systems. For some tips on how to
+54 -46
View File
@@ -19,18 +19,20 @@ servers[^1].
The following example configures a DHCP server for subnet 192.168.2.0/24
with an address pool:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit dhcp-server subnet 192.168.2.0/24</b>
admin@example:/config/dhcp-server/…/192.168.2.0/24/> <b>set pool start-address 192.168.2.100 end-address 192.168.2.200</b>
admin@example:/config/dhcp-server/…/192.168.2.0/24/> <b>leave</b>
</code></pre>
```
admin@example:/> configure
admin@example:/config/> edit dhcp-server subnet 192.168.2.0/24
admin@example:/config/dhcp-server/…/192.168.2.0/24/> set pool start-address 192.168.2.100 end-address 192.168.2.200
admin@example:/config/dhcp-server/…/192.168.2.0/24/> leave
```
When setting up the server from the CLI, the system automatically adds a
few default DHCP options that will be sent to clients: both DNS server
and default gateway will use the system address on the matching
interface.
<pre class="cli"><code>admin@example:/> <b>show running-config</b>
```
admin@example:/> show running-config
"infix-dhcp-server:dhcp-server": {
"subnet": [
{
@@ -52,7 +54,7 @@ interface.
}
]
}
</code></pre>
```
> [!IMPORTANT]
> Remember to set up an interface in this subnet, avoid using addresses
@@ -66,21 +68,23 @@ interface.
To reserve specific IP addresses for clients based on their MAC address,
hostname, or client ID:
<pre class="cli"><code>admin@example:/config/dhcp-server/…/192.168.2.0/24/> <b>edit host 192.168.2.10</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>set match mac-address 00:11:22:33:44:55</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>set hostname printer</b>
admin@example:/config/dhcp-server/…/192.168.2.10/> <b>leave</b>
</code></pre>
```
admin@example:/config/dhcp-server/…/192.168.2.0/24/> edit host 192.168.2.10
admin@example:/config/dhcp-server/…/192.168.2.10/> set match mac-address 00:11:22:33:44:55
admin@example:/config/dhcp-server/…/192.168.2.10/> set hostname printer
admin@example:/config/dhcp-server/…/192.168.2.10/> leave
```
Match hosts using a client identifier instead of MAC address:
<pre class="cli"><code>admin@example:/config/dhcp-server/…/192.168.1.0/24/> <b>edit host 192.168.1.50</b>
admin@example:/config/dhcp-server/…/192.168.1.50/> <b>edit match</b>
admin@example:/config/dhcp-server/…/match/> <b>set client-id hex c0:ff:ee</b>
admin@example:/config/dhcp-server/…/match/> <b>leave</b>
admin@example:/config/dhcp-server/…/192.168.1.50/> <b>set lease-time infinite</b>
admin@example:/config/dhcp-server/…/192.168.1.50/> <b>leave</b>
</code></pre>
```
admin@example:/config/dhcp-server/…/192.168.1.0/24/> edit host 192.168.1.50
admin@example:/config/dhcp-server/…/192.168.1.50/> edit match
admin@example:/config/dhcp-server/…/match/> set client-id hex c0:ff:ee
admin@example:/config/dhcp-server/…/match/> leave
admin@example:/config/dhcp-server/…/192.168.1.50/> set lease-time infinite
admin@example:/config/dhcp-server/…/192.168.1.50/> leave
```
The `hex` prefix here ensures matching of client ID is done using the
hexadecimal octets `c0:ff:ee`, three bytes. Without the prefix the
@@ -96,30 +100,32 @@ ASCII string "c0:ff:ee", eight bytes, is used.
Configure additional DHCP options globally, per subnet, or per host:
<pre class="cli"><code>admin@example:/config/dhcp-server/> <b>edit subnet 192.168.2.0/24</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>edit option dns-server</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/dns-server/> <b>set address 8.8.8.8</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/dns-server/> <b>leave</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>edit option ntp-server</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/ntp-server/> <b>set address 192.168.2.1</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/ntp-server/> <b>leave</b>
</code></pre>
```
admin@example:/config/dhcp-server/> edit subnet 192.168.2.0/24
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> edit option dns-server
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/dns-server/> set address 8.8.8.8
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/dns-server/> leave
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> edit option ntp-server
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/ntp-server/> set address 192.168.2.1
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/option/ntp-server/> leave
```
When configuring, e.g., `dns-server`, or `router` options with the value
`auto`, the system uses the IP address from the interface matching the
subnet. For example:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
```
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
eth0 ethernet UP 02:00:00:00:00:00
ipv4 192.168.1.1/24 (static)
eth1 ethernet UP 02:00:00:00:00:01
ipv4 192.168.2.1/24 (static)
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> <b>edit option dns-server</b>
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/option/dns-server/> <b>set address auto</b>
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/option/dns-server/> <b>leave</b>
</code></pre>
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> edit option dns-server
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/option/dns-server/> set address auto
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/option/dns-server/> leave
```
In this case, clients in subnet 192.168.1.0/24 will receive 192.168.1.1
as their DNS server address.
@@ -129,27 +135,29 @@ as their DNS server address.
Configure DHCP for multiple networks:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit dhcp-server</b>
admin@example:/config/dhcp-server/> <b>edit subnet 192.168.1.0/24</b>
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> <b>set pool start-address 192.168.1.100 end-address 192.168.1.200</b>
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> <b>leave</b>
admin@example:/config/dhcp-server/> <b>edit subnet 192.168.2.0/24</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>set pool start-address 192.168.2.100 end-address 192.168.2.200</b>
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> <b>leave</b>
</code></pre>
```
admin@example:/> configure
admin@example:/config/> edit dhcp-server
admin@example:/config/dhcp-server/> edit subnet 192.168.1.0/24
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> set pool start-address 192.168.1.100 end-address 192.168.1.200
admin@example:/config/dhcp-server/subnet/192.168.1.0/24/> leave
admin@example:/config/dhcp-server/> edit subnet 192.168.2.0/24
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> set pool start-address 192.168.2.100 end-address 192.168.2.200
admin@example:/config/dhcp-server/subnet/192.168.2.0/24/> leave
```
## Monitoring
View active leases and server statistics:
<pre class="cli"><code>admin@example:/> <b>show dhcp-server</b>
<span class="header">IP ADDRESS MAC HOSTNAME CLIENT ID EXPIRES</span>
```
admin@example:/> show dhcp-server
IP ADDRESS MAC HOSTNAME CLIENT ID EXPIRES
192.168.2.22 00:a0:85:00:02:05 00:c0:ff:ee 3591s
192.168.1.11 00:a0:85:00:04:06 foo 01:00:a0:85:00:04:06 3591s
admin@example:/> <b>show dhcp-server statistics</b>
admin@example:/> show dhcp-server statistics
DHCP offers sent : 6
DHCP ACK messages sent : 5
DHCP NAK messages sent : 0
@@ -158,7 +166,7 @@ DHCP discover messages received : 6
DHCP request messages received : 5
DHCP release messages received : 6
DHCP inform messages received : 6
</code></pre>
```
[^1]: This requires the system DNS resolver to be configured.
-208
View File
@@ -1,208 +0,0 @@
# Ethernet Interfaces
This document covers VLAN interfaces, physical Ethernet interfaces,
and virtual Ethernet (VETH) pairs.
## VLAN Interfaces
Creating a VLAN can be done in many ways. This section assumes VLAN
interfaces created atop another Linux interface. E.g., the VLAN
interfaces created on top of the Ethernet interface or bridge in the
picture below.
![VLAN interface on top of Ethernet or Bridge interfaces](img/interface-vlan-variants.svg)
A VLAN interface is basically a filtering abstraction. When you run
`tcpdump` on a VLAN interface you will only see the frames matching the
VLAN ID of the interface, compared to *all* the VLAN IDs if you run
`tcpdump` on the lower-layer interface.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0.20</b>
admin@example:/config/interface/eth0.20/> <b>show</b>
type vlan;
vlan {
tag-type c-vlan;
id 20;
lower-layer-if eth0;
}
admin@example:/config/interface/eth0.20/> <b>leave</b>
</code></pre>
The example below assumes bridge br0 is already created, see [VLAN
Filtering Bridge](bridging.md#vlan-filtering-bridge).
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface vlan10</b>
admin@example:/config/interface/vlan10/> <b>set vlan id 10</b>
admin@example:/config/interface/vlan10/> <b>set vlan lower-layer-if br0</b>
admin@example:/config/interface/vlan10/> <b>leave</b>
</code></pre>
As conventions, a VLAN interface for VID 20 on top of an Ethernet
interface *eth0* is named *eth0.20*, and a VLAN interface for VID 10 on
top of a bridge interface *br0* is named *vlan10*.
> [!NOTE]
> If you name your VLAN interface `foo0.N` or `vlanN`, where `N` is a
> number, the CLI infers the interface type automatically.
## Physical Ethernet Interfaces
### Ethernet Settings and Status
Physical Ethernet interfaces provide low-level settings for speed/duplex as
well as packet status and [statistics](#ethernet-statistics).
By default, Ethernet interfaces defaults to auto-negotiating
speed/duplex modes, advertising all speed and duplex modes available.
In the example below, the switch would by default auto-negotiate speed
1 Gbit/s on port eth1 and 100 Mbit/s on port eth4, as those are the
highest speeds supported by H1 and H2 respectively.
![4-port Gbit/s switch connected to Gbit and Fast Ethernet Hosts](img/ethernet-autoneg.svg)
The speed and duplex status for the links can be listed as shown
below, assuming the link operational status is 'up'.
<pre class="cli"><code>admin@example:/> <b>show interface eth1</b>
name : eth1
index : 2
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:01
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
...
admin@example:/> <b>show interface eth4</b>
name : eth4
index : 5
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 100
physical address : 00:53:00:06:11:04
ipv4 addresses :
ipv6 addresses :
in-octets : 75439
out-octets : 550704
...
admin@example:/>
</code></pre>
### Configuring fixed speed and duplex
Auto-negotiation of speed/duplex mode is desired in almost all
use-cases, but it is possible to disable auto-negotiation and specify
a fixed speed and duplex mode.
> [!IMPORTANT]
> When setting a fixed speed and duplex mode, ensure both sides of the
> link have matching configuration. If speed does not match, the link
> will not come up. If duplex mode does not match, the result is
> reported collisions and/or bad throughput.
The example below configures port eth3 to fixed speed 100 Mbit/s
half-duplex mode.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth3 ethernet</b>
admin@example:/config/interface/eth3/ethernet/> <b>set speed 0.1</b>
admin@example:/config/interface/eth3/ethernet/> <b>set duplex half</b>
admin@example:/config/interface/eth3/ethernet/> <b>set auto-negotiation enable false</b>
admin@example:/config/interface/eth3/ethernet/> <b>show</b>
auto-negotiation {
enable false;
}
duplex half;
speed 0.1;
admin@example:/config/interface/eth3/ethernet/> <b>leave</b>
admin@example:/>
</code></pre>
Speed metric is in Gbit/s. Auto-negotiation needs to be disabled in
order for fixed speed/duplex to apply. Only speeds `0.1`(100 Mbit/s)
and `0.01` (10 Mbit/s) can be specified. 1 Gbit/s and higher speeds
require auto-negotiation to be enabled.
### Ethernet statistics
Ethernet packet statistics[^1] can be listed as shown below.
<pre class="cli"><code>admin@example:/> <b>show interface eth1</b>
name : eth1
index : 2
mtu : 1500
operational status : up
auto-negotiation : on
duplex : full
speed : 1000
physical address : 00:53:00:06:11:0a
ipv4 addresses :
ipv6 addresses :
in-octets : 75581
out-octets : 43130
eth-in-frames : 434
eth-in-multicast-frames : 296
eth-in-broadcast-frames : 138
eth-in-error-fcs-frames : 0
eth-in-error-oversize-frames : 0
eth-out-frames : 310
eth-out-multicast-frames : 310
eth-out-broadcast-frames : 0
eth-out-good-octets : 76821
eth-in-good-octets : 60598
admin@example:/>
</code></pre>
## VETH Pairs
A Virtual Ethernet (VETH) pair is basically a virtual Ethernet cable. A
cable can be "plugged in" to a bridge and the other end can be given to
a [container](container.md), or plugged into another bridge.
The latter example is useful if you have multiple bridges in the system
with different properties (VLAN filtering, IEEE group forwarding, etc.),
but still want some way of communicating between these domains.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface veth0a</b>
admin@example:/config/interface/veth0a/> <b>set veth peer veth0b</b>
admin@example:/config/interface/veth0a/> <b>end</b>
admin@example:/config/> <b>diff</b>
interfaces {
+ interface veth0a {
+ type veth;
+ veth {
+ peer veth0b;
+ }
+ }
+ interface veth0b {
+ type veth;
+ veth {
+ peer veth0a;
+ }
+ }
}
admin@example:/config/>
</code></pre>
> [!TIP]
> This is another example of the automatic inference of the interface
> type from the name. Any name can be used, but then you have to set
> the interface type to `veth` manually.
[^1]: Ethernet counters are described in *ieee802-ethernet-interface.yang*
and *infix-ethernet-interface.yang*. There is a dedicated document on
[Ethernet Counters](eth-counters.md) that provide additional details
on the statistics support.
-11
View File
@@ -24,14 +24,3 @@
/* Reset alignment for table cells */
text-align: initial;
}
/* CLI terminal output styling */
.md-typeset pre.cli .title {
font-weight: bold;
}
.md-typeset pre.cli .header {
background-color: #e0e0e0;
color: #1a1a1a;
font-weight: bold;
}
+20 -24
View File
@@ -93,7 +93,7 @@ about this in the [example below](#end-device-protection).
> [!IMPORTANT] Remember IP forwarding on interfaces!
> Firewall policies only control whether traffic is allowed on input, to be
> forwarded, or blocked (default). For the actual routing between interfaces
> to work, you must also enable [IP forwarding](ip.md#ipv4-forwarding)
> to work, you must also enable [IP forwarding](networking.md#ipv4-forwarding)
> on the relevant interfaces.
### Intra-Zone Traffic
@@ -151,16 +151,15 @@ allowed access to.
See the [examples below](#enterprise-gateway) for how to set up a policy. The
built-in help system can also be useful:
<pre class="cli"><code>admin@example:/config/firewall/policy/lan-to-dmz/> <b>help masquerade</b>
<code><pre>admin@example:/config/firewall/policy/lan-to-dmz/> <b>help masquerade</b>
<b>NAME</b>
masquerade <true/false><br/>
<b>DESCRIPTION</b>
Enable masquerading (SNAT) for traffic matching this policy.<br/>
Matching traffic will have their source IP address changed on egress,
using the IP address of the interface the traffic egresses.<br/>
using the IP address of the interface the traffic egresses.";<br/>
admin@example:/config/firewall/policy/lan-to-dmz/>
</code></pre>
</pre></code>
### Symbolic Names
@@ -230,8 +229,7 @@ The firewall includes over 100 pre-defined services, such as:
This is the default firewall setup, useful for end devices on untrusted
networks. It provides maximum protection while allowing essential
connectivity.
<pre class="cli"><code>admin@example:/> <b>configure</b>
<code><pre>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit firewall</b>
admin@example:/config/firewall/> <b>show</b>
default public;
@@ -242,21 +240,21 @@ zone public {
service ssh;
}
admin@example:/config/firewall/> <b>leave</b>
</code></pre>
</pre></code>
The `reject` action differs from `drop` in that it responds to ICMP messages,
although maybe not how you may think. Pinging the device we may[^1] see this:
<pre class="cli"><code><b>$</b> ping 192.168.122.161
<code><pre>
<b>$</b> ping 192.168.122.161
From 192.168.122.161 icmp_seq=1 <u>Packet filtered</u>
</code></pre>
</pre></code>
If we run `tcpdump` it shows us why:
<pre class="cli"><code><b>$</b> tcpdump -lni eth0
<code><pre>
<b>$</b> tcpdump -lni eth0
20:10:40.245707 IP 192.168.122.1 > 192.168.122.161: ICMP echo request, id 56838, seq 1, length 64
20:10:40.245961 IP 192.168.122.161 > 192.168.122.1: ICMP <u>host 192.168.122.161 unreachable - admin prohibited filter</u>, length 92
</code></pre>
</pre></code>
The key here is that, yes the device responds, but not with `ICMP reply` but
`ICMP unreachable`, and a little helpful message.
@@ -287,8 +285,7 @@ Zone matrix and firewall overview from <kbd>show firewall</kbd>.
For typical routers that need to protect internal devices while providing
internet access. The LAN zone trusts internal devices, while the WAN zone
blocks external threats.
<pre class="cli"><code>admin@example:/> <b>configure</b>
<code><pre>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit firewall</b>
admin@example:/config/firewall/> <b>set default wan</b>
admin@example:/config/firewall/> <b>edit zone lan</b>
@@ -311,15 +308,14 @@ admin@example:/config/firewall/…/loc-to-wan/> <b>set egress wan</b>
admin@example:/config/firewall/…/loc-to-wan/> <b>set action accept</b>
admin@example:/config/firewall/…/loc-to-wan/> <b>set masquerade</b>
admin@example:/config/firewall/…/loc-to-wan/> <b>leave</b>
</code></pre>
</pre></code>
### Enterprise Gateway
For businesses that need to host public services while protecting internal
resources. We can build upon the Home/Office Router example above and add
a DMZ zone with additional policies for controlled access.
<pre class="cli"><code>admin@example:/> <b>configure</b>
<code><pre>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit firewall zone dmz</b>
admin@example:/config/firewall/…/dmz/> <b>set description "Semi-trusted public services"</b>
admin@example:/config/firewall/…/dmz/> <b>set action drop</b>
@@ -343,7 +339,7 @@ admin@example:/config/firewall/> <b>edit zone wan port-forward 8080 tcp</b>
admin@example:/config/firewall/…/tcp/> <b>set to addr 192.168.2.10</b>
admin@example:/config/firewall/…/tcp/> <b>set to port 80</b>
admin@example:/config/firewall/…/tcp/> <b>leave</b>
</code></pre>
</pre></code>
This adds a DMZ zone for public services, updates the internet access policy
to include DMZ traffic, allows LAN management of DMZ services, and forwards
@@ -353,12 +349,12 @@ external web traffic to the DMZ server.
Different log levels are available to monitor and debug firewall behavior.
Configure logging using the CLI:
<pre class="cli"><code>admin@example:/> <b>configure</b>
<code><pre>
admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit firewall</b>
admin@example:/config/firewall/> <b>set logging all</b>
admin@example:/config/firewall/> <b>leave</b>
</code></pre>
</pre></code>
Firewall logs help you understand traffic patterns and security events. The
CLI admin-exec command <kbd>show firewall</kbd> shows the last 10 log messages in the
@@ -461,4 +457,4 @@ You can check the current lockdown state:
}
```
[1]: bridging.md
[1]: networking.md#bridging
+17 -27
View File
@@ -8,7 +8,7 @@ hardware][1], with deviations and augmentations in _infix-hardware_.
For Infix to be able to control USB port(s), a device tree modification
is needed (see _alder.dtsi_ for full example).
```json
```
chosen {
infix {
usb-ports = <&cp0_usb3_1>;
@@ -24,38 +24,26 @@ All USB ports in the system will be disabled during boot due to the file
Infix to control USB port(s), remove the file or manually enable the USB
bus, here is an example:
```bash
```
# Enable the bus
echo 1 > /sys/bus/usb/devices/usb1/authorized
```
And then enable sub-devices (e.g. USB memory)
```bash
```
# Enable a device plugged into usb1
echo 1 > /sys/bus/usb/devices/usb1/1-1/authorized
```
### Current status
<pre class="cli"><code>admin@example:/> <b>show hardware</b>
<span class="header">HARDWARE COMPONENTS </span>
──────────────────────────────────────────────────────────────
<span class="title">Board Information </span>
Model : FriendlyElec NanoPi R2S
Manufacturer : FriendlyElec
Serial Number : 9d1fbfdab6d171ce
Base MAC Address : 4a:dc:d8:20:0d:85
──────────────────────────────────────────────────────────────
<span class="title">USB Ports </span>
<span class="header">NAME STATE OPER </span>
USB unlocked enabled
──────────────────────────────────────────────────────────────
<span class="title">Sensors </span>
<span class="header">NAME VALUE STATUS </span>
soc 44.1 °C ok
soc 44.5 °C ok
</code></pre>
```
admin@example:/> show hardware
USB PORTS
NAME STATE
USB unlocked
```
An USB port can be in two states _unlocked_ and _locked_. When a port is
locked, all connected devices will get power, but never authorized by
@@ -68,11 +56,12 @@ Linux to use.
> command `show hardware` in admin-exec context. (Use `do` prefix in
> configure context.)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>set hardware component USB state admin-state unlocked</b>
admin@example:/config/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> set hardware component USB state admin-state unlocked
admin@example:/config/> leave
admin@example:/>
</code></pre>
```
### Using a USB Stick
@@ -92,7 +81,8 @@ The only way currently to safely "eject" a USB memory stick is to use
`umount` command from a UNIX shell, which explicitly synchronizes any
cached data to disk before returning the prompt:
<pre class="cli"><code>admin@example:~$ <b>sudo umount /media/log</b>
</code></pre>
```
admin@example:~$ sudo umount /media/log
```
[1]: https://www.rfc-editor.org/rfc/rfc8348.html
-143
View File
@@ -1,143 +0,0 @@
# Common Interface Settings
Common interface settings include `name`, `type`, `enabled`, `description`,
and custom MAC address. Type-specific settings are covered in the dedicated
sections for [Bridging](bridging.md), [Link Aggregation](lag.md),
[Ethernet](ethernet.md), [IP Addressing](ip.md), and [Routing](routing.md).
## Interface Name
The interface name is limited to 1-15 characters due to Linux kernel
constraints. Physical interfaces use their system-assigned names (e.g.,
`eth0`, `eth1`), while user-created interfaces can be named freely within
this limit.
> [!TIP]
> Naming conventions like `br0`, `lag0`, `vlan10`, or `eth0.20` allow
> the CLI to automatically infer the interface type.
## Interface Type
The `type` setting defines what kind of interface this is: `bridge`, `lag`,
`vlan`, `veth`, etc. When configuring via the CLI, the type is often
inferred from the interface name. However, when configuring remotely via
NETCONF or RESTCONF, the type *must* be set explicitly.
<pre class="cli"><code>admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>set type bridge</b>
</code></pre>
Available types can be listed from the CLI:
<pre class="cli"><code>admin@example:/config/interface/br0/> <b>set type ?</b>
bridge IEEE bridge interface.
dummy Linux dummy interface. Useful mostly for testing.
ethernet Any Ethernet interfaces, regardless of speed, RFC 3635.
gre GRE tunnel interface.
gretap GRETAP (Ethernet over GRE) tunnel interface.
lag IEEE link aggregate interface.
loopback Linux loopback interface.
other Other interface, i.e., unknown.
veth Linux virtual Ethernet pair.
vlan Layer 2 Virtual LAN using 802.1Q.
vxlan Virtual eXtensible LAN tunnel interface.
wifi WiFi (802.11) interface
wireguard WireGuard VPN tunnel interface.
</code></pre>
## Enable/Disable
An interface can be administratively disabled using the `enabled` setting.
By default, interfaces are enabled (`true`).
<pre class="cli"><code>admin@example:/config/> <b>edit interface eth0</b>
admin@example:/config/interface/eth0/> <b>set enabled false</b>
admin@example:/config/interface/eth0/> <b>leave</b>
</code></pre>
The operational status can be inspected to see both administrative and
actual link state:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
INTERFACE PROTOCOL STATE DATA
eth0 ethernet <b>DISABLED</b> 02:00:00:00:00:00
eth1 ethernet UP 02:00:00:00:00:01
...
</code></pre>
## Description
The `description` is a free-form text string (max 64 characters) saved
as the Linux interface alias (`ifalias`). Use it to document an interface's
purpose or add notes for remote debugging.
<pre class="cli"><code>admin@example:/config/> <b>edit interface eth0</b>
admin@example:/config/interface/eth0/> <b>set description "Uplink to core switch"</b>
admin@example:/config/interface/eth0/> <b>leave</b>
</code></pre>
The description is visible in the operational datastore and in `show`
commands:
<pre class="cli"><code>admin@example:/> <b>show interface eth0</b>
name : eth0
description : Uplink to core switch
index : 2
...
</code></pre>
## Custom MAC Address
The `custom-phys-address` can be used to set an interface's MAC address.
This is an extension to the ietf-interfaces YANG model, which defines
`phys-address` as read-only[^1].
> [!CAUTION]
> There is no validation or safety checks performed by the system when
> using `custom-phys-address`. In particular the `offset` variant can
> be dangerous to use -- pay attention to the meaning of bits in the
> upper-most octet: local bit, multicast/group, etc.
### Fixed custom MAC
Use a fixed custom MAC address when the interface must present a
specific, deterministic identity on the network. This option bypasses
any chassis-derived logic and applies the configured address verbatim.
<pre class="cli"><code>admin@example:/config/> <b>edit interface veth0a</b>
admin@example:/config/interface/veth0a/> <b>set custom-phys-address static 00:ab:00:11:22:33</b>
=> 00:ab:00:11:22:33
</code></pre>
### Chassis MAC
Chassis MAC, sometimes also referred to as base MAC. In these two
examples it is `00:53:00:c0:ff:ee`.
<pre class="cli"><code>admin@example:/config/> <b>edit interface veth0a</b>
admin@example:/config/interface/veth0a/> <b>set custom-phys-address chassis</b>
=> 00:53:00:c0:ff:ee
</code></pre>
### Chassis MAC, with offset
When constructing a derived address it is recommended to set the locally
administered bit. Same chassis MAC as before.
<pre class="cli"><code>admin@example:/config/> <b>edit interface veth0a</b>
admin@example:/config/interface/veth0a/> <b>set custom-phys-address chassis offset 02:00:00:00:00:02</b>
=> 02:53:00:c0:ff:f0
</code></pre>
[^1]: A YANG deviation was previously used to make it possible to set
`phys-address`, but this has been replaced with the more flexible
`custom-phys-address`.
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 250 KiB

-983
View File
@@ -1,983 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 700 500"
version="1.1"
id="svg220"
sodipodi:docname="vpn-hub-spoke.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview222"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.8885714"
inkscape:cx="350.00001"
inkscape:cy="225.56733"
inkscape:window-width="1920"
inkscape:window-height="1014"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg220" />
<defs
id="defs40">
<linearGradient
id="bgGrad"
x1="0%"
y1="0%"
x2="100%"
y2="100%">
<stop
offset="0%"
style="stop-color:#fafbfc;stop-opacity:1"
id="stop2" />
<stop
offset="100%"
style="stop-color:#f3f4f6;stop-opacity:1"
id="stop4" />
</linearGradient>
<linearGradient
id="siteGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#3b82f6;stop-opacity:1"
id="stop7" />
<stop
offset="100%"
style="stop-color:#2563eb;stop-opacity:1"
id="stop9" />
</linearGradient>
<linearGradient
id="routerGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#ef4444;stop-opacity:1"
id="stop12" />
<stop
offset="100%"
style="stop-color:#dc2626;stop-opacity:1"
id="stop14" />
</linearGradient>
<linearGradient
id="hubGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#f59e0b;stop-opacity:1"
id="stop17" />
<stop
offset="100%"
style="stop-color:#d97706;stop-opacity:1"
id="stop19" />
</linearGradient>
<filter
id="shadow"
x="-0.054666667"
y="-0.082"
width="1.1093333"
height="1.184">
<feGaussianBlur
in="SourceAlpha"
stdDeviation="3"
id="feGaussianBlur22" />
<feOffset
dx="0"
dy="2"
result="offsetblur"
id="feOffset24" />
<feComponentTransfer
id="feComponentTransfer28">
<feFuncA
type="linear"
slope="0.2"
id="feFuncA26" />
</feComponentTransfer>
<feMerge
id="feMerge34">
<feMergeNode
id="feMergeNode30" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode32" />
</feMerge>
</filter>
<marker
id="arrow"
markerWidth="8"
markerHeight="8"
refX="7"
refY="4"
orient="auto">
<path
d="M 0,0 V 8 L 8,4 Z"
fill="#10b981"
id="path37" />
</marker>
<radialGradient
id="cloudGrad"
cx="220.99805"
cy="209.29596"
gradientTransform="matrix(1.3416408,0,0,0.74535599,215.52724,137.78745)"
fx="220.99805"
fy="209.29596"
r="51.988579"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
style="stop-color:#ffffff;stop-opacity:1"
id="stop22" />
<stop
offset="70%"
style="stop-color:#dbeafe;stop-opacity:1"
id="stop24" />
<stop
offset="100%"
style="stop-color:#93c5fd;stop-opacity:1"
id="stop26" />
</radialGradient>
<filter
id="shadow-7"
x="-0.061678832"
y="-0.11266667"
width="1.1233577"
height="1.252">
<feGaussianBlur
in="SourceAlpha"
stdDeviation="3"
id="feGaussianBlur29" />
<feOffset
dx="0"
dy="2"
result="offsetblur"
id="feOffset31" />
<feComponentTransfer
id="feComponentTransfer35">
<feFuncA
type="linear"
slope="0.2"
id="feFuncA33" />
</feComponentTransfer>
<feMerge
id="feMerge41">
<feMergeNode
id="feMergeNode37" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode39" />
</feMerge>
</filter>
</defs>
<style
id="style26">
@media (prefers-color-scheme: dark) {
#bgGrad stop:first-child { stop-color: #1f2937; }
#bgGrad stop:last-child { stop-color: #111827; }
#siteGrad stop:first-child { stop-color: #2563eb; }
#siteGrad stop:last-child { stop-color: #1e40af; }
#routerGrad stop:first-child { stop-color: #dc2626; }
#routerGrad stop:last-child { stop-color: #b91c1c; }
#hubGrad stop:first-child { stop-color: #f59e0b; }
#hubGrad stop:last-child { stop-color: #d97706; }
rect[fill=&quot;#fff&quot;], rect[fill=&quot;#ffffff&quot;] { fill: #374151; }
rect[stroke=&quot;#e5e7eb&quot;] { stroke: #4b5563; }
text[fill=&quot;#6b7280&quot;] { fill: #d1d5db; }
circle[fill=&quot;#60a5fa&quot;] { fill: #3b82f6; }
line[stroke=&quot;#94a3b8&quot;] { stroke: #6b7280; }
rect[fill=&quot;#fbbf24&quot;] { fill: #f59e0b; }
rect[fill=&quot;#fca5a5&quot;] { fill: #fca5a5; }
}
</style>
<!-- Physical Internet connections (solid lines) -->
<!-- VPN Tunnels -->
<line
x1="149.87024"
y1="94.852066"
x2="262.66898"
y2="194.88768"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10,6"
marker-end="url(#arrow)"
id="line44" />
<g
transform="translate(155,83)"
id="g52">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect46"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path48" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle50" />
</g>
<line
x1="550.13788"
y1="94.850327"
x2="437.03882"
y2="193.65047"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10,6"
marker-end="url(#arrow)"
id="line54" />
<g
transform="translate(537,83)"
id="g62">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect56"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path58" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle60" />
</g>
<line
x1="348.10764"
y1="399.8786"
x2="348.10764"
y2="311.25961"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10, 6"
marker-end="url(#arrow)"
id="line64" />
<g
transform="translate(346,383)"
id="g72">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect66"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path68" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle70" />
</g>
<!-- Hub (Center) -->
<g
filter="url(#shadow)"
id="g114">
<rect
x="260"
y="195"
width="180"
height="110"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect82" />
<!-- Header -->
<rect
x="260"
y="195"
width="180"
height="38"
rx="12"
fill="url(#siteGrad)"
id="rect84" />
<rect
x="260"
y="220"
width="180"
height="13"
fill="url(#siteGrad)"
id="rect86" />
<text
x="350"
y="220"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="15"
font-weight="700"
fill="#fff"
id="text88">Headquarters</text>
<!-- Hub Router -->
<rect
x="278"
y="243"
width="144"
height="38"
rx="8"
fill="url(#hubGrad)"
id="rect90" />
<rect
x="280"
y="245"
width="140"
height="18"
rx="6"
fill="#fbbf24"
opacity="0.3"
id="rect92" />
<text
x="350"
y="267"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="13"
font-weight="700"
fill="#fff"
id="text94">HUB</text>
<!-- Local Network -->
<line
x1="260"
y1="250"
x2="180"
y2="250"
stroke="#94a3b8"
stroke-width="1.5"
id="line96" />
<line
x1="180"
y1="220"
x2="180"
y2="280"
stroke="#94a3b8"
stroke-width="1.5"
id="line98" />
<circle
cx="172"
cy="225"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle100" />
<line
x1="180"
y1="225"
x2="174"
y2="225"
stroke="#94a3b8"
stroke-width="1"
id="line102" />
<circle
cx="172"
cy="250"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle104" />
<line
x1="180"
y1="250"
x2="174"
y2="250"
stroke="#94a3b8"
stroke-width="1"
id="line106" />
<circle
cx="172"
cy="275"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle108" />
<line
x1="180"
y1="275"
x2="174"
y2="275"
stroke="#94a3b8"
stroke-width="1"
id="line110" />
<text
x="130"
y="252"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="8"
font-weight="600"
fill="#6b7280"
id="text112">192.168.0.0/24</text>
</g>
<!-- Spoke A (Top Left) -->
<g
filter="url(#shadow)"
id="g148">
<rect
x="40"
y="30"
width="150"
height="100"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect116" />
<!-- Header -->
<rect
x="40"
y="30"
width="150"
height="32"
rx="12"
fill="url(#siteGrad)"
id="rect118" />
<rect
x="40"
y="51"
width="150"
height="11"
fill="url(#siteGrad)"
id="rect120" />
<text
x="115"
y="51"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="14"
font-weight="700"
fill="#fff"
id="text122">Branch A</text>
<!-- Router -->
<rect
x="55"
y="70"
width="120"
height="30"
rx="6"
fill="url(#routerGrad)"
id="rect124" />
<rect
x="57"
y="72"
width="116"
height="14"
rx="4"
fill="#fca5a5"
opacity="0.3"
id="rect126" />
<text
x="115"
y="89"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="11"
font-weight="600"
fill="#fff"
id="text128">Spoke</text>
<!-- Local Network -->
<line
x1="115"
y1="100"
x2="115"
y2="107"
stroke="#94a3b8"
stroke-width="1.5"
id="line130" />
<line
x1="90"
y1="107"
x2="140"
y2="107"
stroke="#94a3b8"
stroke-width="1.5"
id="line132" />
<circle
cx="95"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle134" />
<line
x1="95"
y1="107"
x2="95"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line136" />
<circle
cx="115"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle138" />
<line
x1="115"
y1="107"
x2="115"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line140" />
<circle
cx="135"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle142" />
<line
x1="135"
y1="107"
x2="135"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line144" />
<text
x="115"
y="128"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="7"
font-weight="600"
fill="#6b7280"
id="text146">192.168.1.0/24</text>
</g>
<!-- Spoke B (Top Right) -->
<g
filter="url(#shadow)"
id="g182">
<rect
x="510"
y="30"
width="150"
height="100"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect150" />
<!-- Header -->
<rect
x="510"
y="30"
width="150"
height="32"
rx="12"
fill="url(#siteGrad)"
id="rect152" />
<rect
x="510"
y="51"
width="150"
height="11"
fill="url(#siteGrad)"
id="rect154" />
<text
x="585"
y="51"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="14"
font-weight="700"
fill="#fff"
id="text156">Branch B</text>
<!-- Router -->
<rect
x="525"
y="70"
width="120"
height="30"
rx="6"
fill="url(#routerGrad)"
id="rect158" />
<rect
x="527"
y="72"
width="116"
height="14"
rx="4"
fill="#fca5a5"
opacity="0.3"
id="rect160" />
<text
x="585"
y="89"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="11"
font-weight="600"
fill="#fff"
id="text162">Spoke</text>
<!-- Local Network -->
<line
x1="585"
y1="100"
x2="585"
y2="107"
stroke="#94a3b8"
stroke-width="1.5"
id="line164" />
<line
x1="560"
y1="107"
x2="610"
y2="107"
stroke="#94a3b8"
stroke-width="1.5"
id="line166" />
<circle
cx="565"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle168" />
<line
x1="565"
y1="107"
x2="565"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line170" />
<circle
cx="585"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle172" />
<line
x1="585"
y1="107"
x2="585"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line174" />
<circle
cx="605"
cy="115"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle176" />
<line
x1="605"
y1="107"
x2="605"
y2="113"
stroke="#94a3b8"
stroke-width="1"
id="line178" />
<text
x="585"
y="125"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="7"
font-weight="600"
fill="#6b7280"
id="text180">192.168.2.0/24</text>
</g>
<!-- Spoke C (Bottom) -->
<g
filter="url(#shadow)"
id="g216">
<rect
x="275"
y="370"
width="150"
height="100"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect184" />
<!-- Header -->
<rect
x="275"
y="370"
width="150"
height="32"
rx="12"
fill="url(#siteGrad)"
id="rect186" />
<rect
x="275"
y="391"
width="150"
height="11"
fill="url(#siteGrad)"
id="rect188" />
<text
x="350"
y="391"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="14"
font-weight="700"
fill="#fff"
id="text190">Branch C</text>
<!-- Router -->
<rect
x="290"
y="410"
width="120"
height="30"
rx="6"
fill="url(#routerGrad)"
id="rect192" />
<rect
x="292"
y="412"
width="116"
height="14"
rx="4"
fill="#fca5a5"
opacity="0.3"
id="rect194" />
<text
x="350"
y="429"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="11"
font-weight="600"
fill="#fff"
id="text196">Spoke</text>
<!-- Local Network -->
<line
x1="350"
y1="440"
x2="350"
y2="447"
stroke="#94a3b8"
stroke-width="1.5"
id="line198" />
<line
x1="325"
y1="447"
x2="375"
y2="447"
stroke="#94a3b8"
stroke-width="1.5"
id="line200" />
<circle
cx="330"
cy="455"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle202" />
<line
x1="330"
y1="447"
x2="330"
y2="453"
stroke="#94a3b8"
stroke-width="1"
id="line204" />
<circle
cx="350"
cy="455"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle206" />
<line
x1="350"
y1="447"
x2="350"
y2="453"
stroke="#94a3b8"
stroke-width="1"
id="line208" />
<circle
cx="370"
cy="455"
r="4"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle210" />
<line
x1="370"
y1="447"
x2="370"
y2="453"
stroke="#94a3b8"
stroke-width="1"
id="line212" />
<text
x="350"
y="465"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="7"
font-weight="600"
fill="#6b7280"
id="text214">192.168.3.0/24</text>
</g>
<g
transform="matrix(0.98466939,0,0,1.0000859,498.17175,113.77759)"
id="g97">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect91"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path93" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle95" />
</g>
<text
x="446.42084"
y="148.79063"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="10.9158px"
font-weight="600"
fill="#059669"
id="text99"
transform="scale(0.99226244,1.0077979)"
style="stroke-width:0.992348">Encrypted VPN</text>
<g
transform="matrix(0.98466939,0,0,1.0000859,193.71492,114.69643)"
id="g97-3">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect91-6"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path93-7" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle95-5" />
</g>
<text
x="254.16939"
y="144.61209"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="10.9158px"
font-weight="600"
fill="#059669"
id="text99-3"
transform="scale(0.99226244,1.0077979)"
style="stroke-width:0.992348">Encrypted VPN</text>
<g
transform="matrix(0.98466939,0,0,1.0000859,333.47081,353.92815)"
id="g97-5">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect91-62"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path93-9" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle95-1" />
</g>
<text
x="393.52994"
y="352.21753"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="10.9158px"
font-weight="600"
fill="#059669"
id="text99-2"
transform="scale(0.99226244,1.0077979)"
style="stroke-width:0.992348">Encrypted VPN</text>
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

-689
View File
@@ -1,689 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 700 350"
version="1.1"
id="svg171"
sodipodi:docname="vpn-roadwarrior.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview173"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.8885714"
inkscape:cx="350.00001"
inkscape:cy="174.73525"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg171" />
<defs
id="defs47">
<linearGradient
id="bgGrad"
x1="0%"
y1="0%"
x2="100%"
y2="100%">
<stop
offset="0%"
style="stop-color:#fafbfc;stop-opacity:1"
id="stop2" />
<stop
offset="100%"
style="stop-color:#f3f4f6;stop-opacity:1"
id="stop4" />
</linearGradient>
<linearGradient
id="corpGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#3b82f6;stop-opacity:1"
id="stop7" />
<stop
offset="100%"
style="stop-color:#2563eb;stop-opacity:1"
id="stop9" />
</linearGradient>
<linearGradient
id="routerGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#ef4444;stop-opacity:1"
id="stop12" />
<stop
offset="100%"
style="stop-color:#dc2626;stop-opacity:1"
id="stop14" />
</linearGradient>
<linearGradient
id="deviceGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#8b5cf6;stop-opacity:1"
id="stop17" />
<stop
offset="100%"
style="stop-color:#7c3aed;stop-opacity:1"
id="stop19" />
</linearGradient>
<radialGradient
id="cloudGrad"
cx="220.99805"
cy="209.29596"
gradientTransform="scale(1.3416408,0.74535599)"
fx="220.99805"
fy="209.29596"
r="51.98858"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
style="stop-color:#ffffff;stop-opacity:1"
id="stop22" />
<stop
offset="70%"
style="stop-color:#dbeafe;stop-opacity:1"
id="stop24" />
<stop
offset="100%"
style="stop-color:#93c5fd;stop-opacity:1"
id="stop26" />
</radialGradient>
<filter
id="shadow"
x="-0.164"
y="-0.11699244"
width="1.328"
height="1.2563258">
<feGaussianBlur
in="SourceAlpha"
stdDeviation="3"
id="feGaussianBlur29" />
<feOffset
dx="0"
dy="2"
result="offsetblur"
id="feOffset31" />
<feComponentTransfer
id="feComponentTransfer35">
<feFuncA
type="linear"
slope="0.2"
id="feFuncA33" />
</feComponentTransfer>
<feMerge
id="feMerge41">
<feMergeNode
id="feMergeNode37" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode39" />
</feMerge>
</filter>
<marker
id="arrow"
markerWidth="8"
markerHeight="8"
refX="7"
refY="4"
orient="auto">
<path
d="M 0,0 V 8 L 8,4 Z"
fill="#10b981"
id="path44" />
</marker>
</defs>
<style
id="style30">
@media (prefers-color-scheme: dark) {
#bgGrad stop:first-child { stop-color: #1f2937; }
#bgGrad stop:last-child { stop-color: #111827; }
#corpGrad stop:first-child { stop-color: #2563eb; }
#corpGrad stop:last-child { stop-color: #1e40af; }
#routerGrad stop:first-child { stop-color: #dc2626; }
#routerGrad stop:last-child { stop-color: #b91c1c; }
#deviceGrad stop:first-child { stop-color: #4c1d95; }
#deviceGrad stop:last-child { stop-color: #3b0764; }
#cloudGrad stop:first-child { stop-color: #374151; }
#cloudGrad stop:nth-child(2) { stop-color: #1e3a8a; }
#cloudGrad stop:last-child { stop-color: #1e40af; }
rect[fill=&quot;#fff&quot;], rect[fill=&quot;#ffffff&quot;] { fill: #374151; }
rect[stroke=&quot;#e5e7eb&quot;] { stroke: #4b5563; }
text[fill=&quot;#6b7280&quot;] { fill: #d1d5db; }
text[fill=&quot;#1e40af&quot;] { fill: #60a5fa; }
ellipse[fill=&quot;#ffffff&quot;] { fill: #4b5563; }
circle[fill=&quot;#60a5fa&quot;] { fill: #3b82f6; }
line[stroke=&quot;#94a3b8&quot;] { stroke: #6b7280; }
rect[fill=&quot;#1e40af&quot;] { fill: #1e3a8a; }
rect[fill=&quot;#c4b5fd&quot;] { fill: #8b5cf6; }
rect[fill=&quot;#ede9fe&quot;] { fill: #2e1065; }
text[fill=&quot;#5b21b6&quot;] { fill: #9333ea; }
circle[stroke=&quot;#6d28d9&quot;] { stroke: #4c1d95; }
rect[stroke=&quot;#6d28d9&quot;] { stroke: #4c1d95; }
text[fill=&quot;#ef4444&quot;] { fill: #fca5a5; }
}
</style>
<!-- Internet Cloud -->
<!-- Physical Internet connections (solid lines) -->
<line
x1="110"
y1="65"
x2="230"
y2="160"
stroke="#6b7280"
stroke-width="2"
id="inet-laptop" />
<text
x="137.55841"
y="109.12807"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="9px"
font-weight="500"
fill="#ef4444"
id="text-inet-laptop">Unsecure</text>
<line
x1="79.384186"
y1="185.51099"
x2="229.7012"
y2="183.32214"
stroke="#6b7280"
stroke-width="2"
id="inet-phone" />
<text
x="145"
y="194"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="9px"
font-weight="500"
fill="#ef4444"
id="text-inet-phone">Unsecure</text>
<line
x1="105"
y1="292"
x2="230"
y2="190"
stroke="#6b7280"
stroke-width="2"
id="inet-tablet" />
<text
x="143.19562"
y="243.69884"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="9px"
font-weight="500"
fill="#ef4444"
id="text-inet-tablet">Unsecure</text>
<line
x1="513.08228"
y1="155.4146"
x2="344.54852"
y2="156.5854"
stroke="#6b7280"
stroke-width="1.98644"
id="inet-corporate" />
<text
x="430"
y="150"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="9"
font-weight="500"
fill="#ef4444"
id="text-inet-corporate">Unsecure</text>
<!-- VPN Tunnels: Three lines from clients that merge into one line to server -->
<g
transform="matrix(0.98466939,0,0,1.0000859,119.62684,52.989786)"
id="g73">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect67"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path69" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle71" />
</g>
<g
transform="matrix(0.98466939,0,0,1.0000859,87.933449,161.99967)"
id="g81">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect75"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path77" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle79" />
</g>
<g
transform="matrix(0.98466939,0,0,1.0000859,113.62684,307.00955)"
id="g89">
<rect
width="8"
height="10"
rx="1.5"
fill="#10b981"
id="rect83"
x="0"
y="0" />
<path
d="m 1.5,0 v -2.5 a 2.5,2.5 0 0 1 5,0 V 0"
fill="none"
stroke="#10b981"
stroke-width="1.2"
id="path85" />
<circle
cx="4"
cy="6"
r="1.2"
fill="#ffffff"
id="circle87" />
</g>
<g
transform="matrix(0.98466939,0,0,1.0000859,457.18096,186.99924)"
id="g97">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect91"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path93" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle95" />
</g>
<text
x="413.23505"
y="186.04326"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="10.9158px"
font-weight="600"
fill="#059669"
id="text99"
transform="scale(0.99226244,1.0077979)"
style="stroke-width:0.992348">Encrypted VPN</text>
<!-- Laptop Device -->
<g
filter="url(#shadow)"
id="g115">
<rect
x="20"
y="30"
width="90"
height="60"
rx="6"
fill="url(#deviceGrad)"
stroke="#6d28d9"
stroke-width="2"
id="rect103" />
<rect
x="26"
y="36"
width="78"
height="46"
rx="3"
fill="#ede9fe"
id="rect105" />
<rect
x="49"
y="82"
width="32"
height="4"
rx="2"
fill="url(#deviceGrad)"
id="rect107" />
<rect
x="35"
y="86"
width="60"
height="3"
rx="1.5"
fill="url(#deviceGrad)"
id="rect109" />
<text
x="65"
y="63"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="11"
font-weight="600"
fill="#5b21b6"
id="text111">Laptop</text>
<text
x="65"
y="100"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="9"
font-weight="500"
fill="#6b7280"
id="text113">Remote Worker</text>
</g>
<!-- Mobile Phone Device -->
<g
filter="url(#shadow)"
id="g127">
<rect
x="30"
y="145"
width="50"
height="80"
rx="6"
fill="url(#deviceGrad)"
stroke="#6d28d9"
stroke-width="2"
id="rect117" />
<rect
x="36"
y="153"
width="38"
height="56"
rx="3"
fill="#ede9fe"
id="rect119" />
<circle
cx="55"
cy="218"
r="4"
fill="#ede9fe"
stroke="#6d28d9"
stroke-width="1.5"
id="circle121" />
<text
x="55"
y="188"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="10"
font-weight="600"
fill="#5b21b6"
id="text123">Mobile</text>
<text
x="55"
y="240"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="9"
font-weight="500"
fill="#6b7280"
id="text125">On-the-go</text>
</g>
<!-- Tablet Device -->
<g
filter="url(#shadow)"
id="g139">
<rect
x="25"
y="265"
width="80"
height="55"
rx="5"
fill="url(#deviceGrad)"
stroke="#6d28d9"
stroke-width="2"
id="rect129" />
<rect
x="31"
y="271"
width="68"
height="40"
rx="3"
fill="#ede9fe"
id="rect131" />
<circle
cx="65"
cy="313"
r="3.5"
fill="#ede9fe"
stroke="#6d28d9"
stroke-width="1.5"
id="circle133" />
<text
x="65"
y="295"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="10"
font-weight="600"
fill="#5b21b6"
id="text135">Tablet</text>
<text
x="65"
y="335"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="9"
font-weight="500"
fill="#6b7280"
id="text137">Traveling</text>
</g>
<!-- Corporate Network -->
<g
filter="url(#shadow)"
id="g167">
<rect
x="510"
y="80"
width="170"
height="190"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect141" />
<!-- Header -->
<rect
x="510"
y="80"
width="170"
height="45"
rx="12"
fill="url(#corpGrad)"
id="rect143" />
<rect
x="510"
y="105"
width="170"
height="20"
fill="url(#corpGrad)"
id="rect145" />
<text
x="595"
y="108"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="16"
font-weight="700"
fill="#fff"
id="text147">Corporate</text>
<rect
x="545"
y="115"
width="100"
height="18"
rx="9"
fill="#1e40af"
id="rect149" />
<text
x="595"
y="127"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="11"
font-weight="600"
fill="#fff"
id="text151">192.168.0.0/24</text>
<!-- VPN Gateway -->
<rect
x="530"
y="140"
width="130"
height="42"
rx="8"
fill="url(#routerGrad)"
id="rect153" />
<rect
x="532"
y="142"
width="126"
height="20"
rx="6"
fill="#fca5a5"
opacity="0.3"
id="rect155" />
<text
x="595"
y="165"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="13"
font-weight="700"
fill="#fff"
id="text157">VPN Gateway</text>
<!-- Resources -->
<rect
x="530"
y="195"
width="130"
height="60"
rx="8"
fill="#dbeafe"
stroke="#3b82f6"
stroke-width="1.5"
id="rect159" />
<text
x="595"
y="218"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="12"
font-weight="600"
fill="#1e40af"
id="text161">Servers</text>
<text
x="595"
y="232"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="12"
font-weight="600"
fill="#1e40af"
id="text163">Files</text>
<text
x="595"
y="246"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="12"
font-weight="600"
fill="#1e40af"
id="text165">Applications</text>
</g>
<path
d="m 230,175 c 0,-13 8,-23 20,-23 2,-9 10,-15 20,-15 7,0 13,3 17,8 5,-7 13,-11 23,-11 16,0 30,11 32,26 13,1 23,12 23,25 0,13 -11,24 -25,24 h -88 c -13,0 -24,-11 -24,-24 0,-7 3,-13 7,-17 z"
fill="url(#cloudGrad)"
stroke="#3b82f6"
stroke-width="2.5"
stroke-linejoin="round"
id="path51"
style="fill:url(#cloudGrad);filter:url(#shadow)" />
<line
x1="114.70349"
y1="64.990814"
x2="316.56073"
y2="175.00027"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10,6"
id="line59" />
<line
x1="83.621422"
y1="175.41223"
x2="316.59158"
y2="175.58884"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10, 6"
id="line61" />
<line
x1="108.29816"
y1="302.53445"
x2="316.5495"
y2="175.04326"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="10, 6"
id="line63" />
<line
x1="316.56073"
y1="175.00027"
x2="503.64789"
y2="175.00027"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="12,8"
marker-end="url(#arrow)"
id="line65" />
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

-595
View File
@@ -1,595 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 800 300"
version="1.1"
id="svg178"
sodipodi:docname="vpn-site-to-site.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview180"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.6525"
inkscape:cx="400"
inkscape:cy="150.07564"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg178" />
<defs
id="defs42">
<linearGradient
id="bgGrad"
x1="0%"
y1="0%"
x2="100%"
y2="100%">
<stop
offset="0%"
style="stop-color:#fafbfc;stop-opacity:1"
id="stop2" />
<stop
offset="100%"
style="stop-color:#f3f4f6;stop-opacity:1"
id="stop4" />
</linearGradient>
<linearGradient
id="siteGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#3b82f6;stop-opacity:1"
id="stop7" />
<stop
offset="100%"
style="stop-color:#2563eb;stop-opacity:1"
id="stop9" />
</linearGradient>
<linearGradient
id="routerGrad"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#ef4444;stop-opacity:1"
id="stop12" />
<stop
offset="100%"
style="stop-color:#dc2626;stop-opacity:1"
id="stop14" />
</linearGradient>
<radialGradient
id="cloudGrad"
cx="288.08009"
cy="175.75494"
gradientTransform="matrix(1.3416408,0,0,0.74535599,-11.528571,2.8295566)"
fx="288.08009"
fy="175.75494"
r="51.98858"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
style="stop-color:#ffffff;stop-opacity:1"
id="stop17" />
<stop
offset="70%"
style="stop-color:#dbeafe;stop-opacity:1"
id="stop19" />
<stop
offset="100%"
style="stop-color:#93c5fd;stop-opacity:1"
id="stop21" />
</radialGradient>
<filter
id="shadow"
x="-0.061678832"
y="-0.11266667"
width="1.1233577"
height="1.252">
<feGaussianBlur
in="SourceAlpha"
stdDeviation="3"
id="feGaussianBlur24" />
<feOffset
dx="0"
dy="2"
result="offsetblur"
id="feOffset26" />
<feComponentTransfer
id="feComponentTransfer30">
<feFuncA
type="linear"
slope="0.2"
id="feFuncA28" />
</feComponentTransfer>
<feMerge
id="feMerge36">
<feMergeNode
id="feMergeNode32" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode34" />
</feMerge>
</filter>
<marker
id="arrow"
markerWidth="8"
markerHeight="8"
refX="7"
refY="4"
orient="auto">
<path
d="M 0,0 V 8 L 8,4 Z"
fill="#10b981"
id="path39" />
</marker>
</defs>
<style
id="style27">
@media (prefers-color-scheme: dark) {
#bgGrad stop:first-child { stop-color: #1f2937; }
#bgGrad stop:last-child { stop-color: #111827; }
#siteGrad stop:first-child { stop-color: #2563eb; }
#siteGrad stop:last-child { stop-color: #1e40af; }
#routerGrad stop:first-child { stop-color: #dc2626; }
#routerGrad stop:last-child { stop-color: #b91c1c; }
#cloudGrad stop:first-child { stop-color: #374151; }
#cloudGrad stop:nth-child(2) { stop-color: #1e3a8a; }
#cloudGrad stop:last-child { stop-color: #1e40af; }
rect[fill=&quot;#fff&quot;], rect[fill=&quot;#ffffff&quot;] { fill: #374151; }
rect[stroke=&quot;#e5e7eb&quot;] { stroke: #4b5563; }
text[fill=&quot;#6b7280&quot;] { fill: #d1d5db; }
text[fill=&quot;#1e40af&quot;] { fill: #60a5fa; }
ellipse[fill=&quot;#ffffff&quot;] { fill: #4b5563; }
circle[fill=&quot;#60a5fa&quot;] { fill: #3b82f6; }
line[stroke=&quot;#94a3b8&quot;] { stroke: #6b7280; }
rect[fill=&quot;#1e40af&quot;] { fill: #1e3a8a; }
text[fill=&quot;#ef4444&quot;] { fill: #fca5a5; }
}
</style>
<!-- Internet Cloud -->
<!-- Physical Internet connections (solid lines) -->
<line
x1="169.96941"
y1="150.66559"
x2="308.03061"
y2="148.83441"
stroke="#6b7280"
stroke-width="2"
id="inet-left" />
<text
x="240"
y="145"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="10"
font-weight="500"
fill="#ef4444"
id="text-inet-left">Unsecure</text>
<line
x1="630.02637"
y1="143.69931"
x2="437.97366"
y2="143.80069"
stroke="#6b7280"
stroke-width="2"
id="inet-right" />
<text
x="535"
y="138"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="10"
font-weight="500"
fill="#ef4444"
id="text-inet-right">Unsecure</text>
<!-- VPN Tunnel through cloud -->
<g
transform="translate(191.99738,184.62118)"
id="g62">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect56"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path58" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle60" />
</g>
<g
transform="translate(564.75904,184.3387)"
id="g70">
<rect
width="10"
height="12"
rx="2"
fill="#10b981"
id="rect64"
x="0"
y="0" />
<path
d="m 2,0 v -3 a 3,3 0 0 1 6,0 v 3"
fill="none"
stroke="#10b981"
stroke-width="1.5"
id="path66" />
<circle
cx="5"
cy="7"
r="1.5"
fill="#ffffff"
id="circle68" />
</g>
<text
x="513.77582"
y="161.37065"
text-anchor="middle"
font-family="system-ui, '-apple-system', sans-serif"
font-size="12px"
font-weight="600"
fill="#059669"
id="text72">Encrypted VPN Tunnel</text>
<!-- Site A (Left) -->
<g
filter="url(#shadow)"
id="g124">
<rect
x="20"
y="60"
width="170"
height="180"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect76" />
<!-- Header -->
<rect
x="20"
y="60"
width="170"
height="45"
rx="12"
fill="url(#siteGrad)"
id="rect78" />
<rect
x="20"
y="85"
width="170"
height="20"
fill="url(#siteGrad)"
id="rect80" />
<text
x="105"
y="88"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="16"
font-weight="700"
fill="#fff"
id="text82">Main Office</text>
<rect
x="55"
y="95"
width="100"
height="18"
rx="9"
fill="#1e40af"
id="rect84" />
<text
x="105"
y="107"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="11"
font-weight="600"
fill="#fff"
id="text86">192.168.1.0/24</text>
<!-- Router -->
<rect
x="40"
y="125"
width="130"
height="45"
rx="8"
fill="url(#routerGrad)"
id="rect88" />
<rect
x="42"
y="127"
width="126"
height="20"
rx="6"
fill="#fca5a5"
opacity="0.3"
id="rect90" />
<text
x="105"
y="152"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="13"
font-weight="700"
fill="#fff"
id="text92">VPN Gateway</text>
<!-- Local Network -->
<line
x1="105"
y1="170"
x2="105"
y2="195"
stroke="#94a3b8"
stroke-width="1.5"
id="line94" />
<line
x1="65"
y1="195"
x2="145"
y2="195"
stroke="#94a3b8"
stroke-width="1.5"
id="line96" />
<circle
cx="70"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle98" />
<line
x1="70"
y1="195"
x2="70"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line100" />
<circle
cx="105"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle102" />
<line
x1="105"
y1="195"
x2="105"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line104" />
<circle
cx="140"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle106" />
<line
x1="140"
y1="195"
x2="140"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line108" />
<text
x="105"
y="218"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="8"
font-weight="600"
fill="#6b7280"
id="text122">192.168.1.0/24</text>
</g>
<!-- Site B (Right) -->
<g
filter="url(#shadow)"
id="g174">
<rect
x="610"
y="60"
width="170"
height="180"
rx="12"
fill="#fff"
stroke="#e5e7eb"
stroke-width="2"
id="rect126" />
<!-- Header -->
<rect
x="610"
y="60"
width="170"
height="45"
rx="12"
fill="url(#siteGrad)"
id="rect128" />
<rect
x="610"
y="85"
width="170"
height="20"
fill="url(#siteGrad)"
id="rect130" />
<text
x="695"
y="88"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="16"
font-weight="700"
fill="#fff"
id="text132">Branch Office</text>
<rect
x="645"
y="95"
width="100"
height="18"
rx="9"
fill="#1e40af"
id="rect134" />
<text
x="695"
y="107"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="11"
font-weight="600"
fill="#fff"
id="text136">192.168.2.0/24</text>
<!-- Router -->
<rect
x="630"
y="125"
width="130"
height="45"
rx="8"
fill="url(#routerGrad)"
id="rect138" />
<rect
x="632"
y="127"
width="126"
height="20"
rx="6"
fill="#fca5a5"
opacity="0.3"
id="rect140" />
<text
x="695"
y="152"
text-anchor="middle"
font-family="system-ui, -apple-system, sans-serif"
font-size="13"
font-weight="700"
fill="#fff"
id="text142">VPN Gateway</text>
<!-- Local Network -->
<line
x1="695"
y1="170"
x2="695"
y2="195"
stroke="#94a3b8"
stroke-width="1.5"
id="line144" />
<line
x1="655"
y1="195"
x2="735"
y2="195"
stroke="#94a3b8"
stroke-width="1.5"
id="line146" />
<circle
cx="660"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle148" />
<line
x1="660"
y1="195"
x2="660"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line150" />
<circle
cx="695"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle152" />
<line
x1="695"
y1="195"
x2="695"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line154" />
<circle
cx="730"
cy="204"
r="5"
fill="#60a5fa"
stroke="#2563eb"
stroke-width="1"
id="circle156" />
<line
x1="730"
y1="195"
x2="730"
y2="202"
stroke="#94a3b8"
stroke-width="1"
id="line158" />
<text
x="695"
y="218"
text-anchor="middle"
font-family="'SF Mono', 'Monaco', monospace"
font-size="8"
font-weight="600"
fill="#6b7280"
id="text172">192.168.2.0/24</text>
</g>
<path
d="m 308.47143,152.82956 c 0,-13 8,-23 20,-23 2,-9 10,-15 20,-15 7,0 13,3 17,8 5,-7 13,-11 23,-11 16,0 30,11 32,26 13,1 23,12 23,25 0,13 -11,24 -25,24 h -88 c -13,0 -24,-11 -24,-24 0,-7 3,-13 7,-17 z"
fill="url(#cloudGrad)"
stroke="#3b82f6"
stroke-width="2.5"
stroke-linejoin="round"
id="path46"
style="fill:url(#cloudGrad);filter:url(#shadow)" />
<line
x1="188.49466"
y1="166.37616"
x2="604.93829"
y2="166.37616"
stroke="#10b981"
stroke-width="2.6"
stroke-dasharray="12, 8"
marker-end="url(#arrow)"
id="line54" />
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

-785
View File
@@ -1,785 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 900 400"
version="1.1"
id="svg180"
sodipodi:docname="wireguard-allowed-ips.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview182"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.3653333"
inkscape:cx="297.36329"
inkscape:cy="375.00001"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg180" />
<defs
id="defs57">
<!-- Premium Gradients -->
<linearGradient
id="bgGradient"
x1="0"
y1="0"
x2="821.58384"
y2="821.58384"
gradientTransform="matrix(1.0954451,0,0,0.46357119,-0.66009153,-0.49920384)"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
style="stop-color:#f8f9fa;stop-opacity:1"
id="stop2" />
<stop
offset="100%"
style="stop-color:#e9ecef;stop-opacity:1"
id="stop4" />
</linearGradient>
<linearGradient
id="peerGradient"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#748ffc;stop-opacity:1"
id="stop7" />
<stop
offset="100%"
style="stop-color:#5c7cfa;stop-opacity:1"
id="stop9" />
</linearGradient>
<linearGradient
id="networkGradient"
x1="0%"
y1="0%"
x2="0%"
y2="100%">
<stop
offset="0%"
style="stop-color:#51cf66;stop-opacity:1"
id="stop12" />
<stop
offset="100%"
style="stop-color:#40c057;stop-opacity:1"
id="stop14" />
</linearGradient>
<linearGradient
id="tunnelGradient"
gradientTransform="scale(9.797959,0.10206207)"
x1="21.433035"
y1="2767.9234"
x2="70.42283"
y2="2767.9234"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
style="stop-color:#5c7cfa;stop-opacity:0.8"
id="stop17" />
<stop
offset="50%"
style="stop-color:#4c6ef5;stop-opacity:1"
id="stop19" />
<stop
offset="100%"
style="stop-color:#5c7cfa;stop-opacity:0.8"
id="stop21" />
</linearGradient>
<!-- Premium Filters -->
<filter
id="cardShadow"
x="-0.075714286"
y="-0.35333333"
width="1.1514286"
height="1.84">
<feGaussianBlur
in="SourceAlpha"
stdDeviation="4"
id="feGaussianBlur24" />
<feOffset
dx="0"
dy="4"
result="offsetblur"
id="feOffset26" />
<feComponentTransfer
id="feComponentTransfer30">
<feFuncA
type="linear"
slope="0.15"
id="feFuncA28" />
</feComponentTransfer>
<feMerge
id="feMerge36">
<feMergeNode
id="feMergeNode32" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode34" />
</feMerge>
</filter>
<filter
id="glow"
x="-0.015"
y="-inf"
width="1.03"
height="inf">
<feGaussianBlur
stdDeviation="3"
result="coloredBlur"
id="feGaussianBlur39" />
<feMerge
id="feMerge45">
<feMergeNode
in="coloredBlur"
id="feMergeNode41" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode43" />
</feMerge>
</filter>
<marker
id="arrowRight"
markerWidth="12"
markerHeight="12"
refX="9"
refY="6"
orient="auto"
markerUnits="strokeWidth">
<path
d="M 2,2 L 10,6 L 2,10 Z"
fill="#4c6ef5"
id="path48" />
</marker>
<marker
id="arrowLeft"
markerWidth="12"
markerHeight="12"
refX="3"
refY="6"
orient="auto"
markerUnits="strokeWidth">
<path
d="M 10,2 L 2,6 L 10,10 Z"
fill="#4c6ef5"
id="path51" />
</marker>
<marker
id="keyArrow"
markerWidth="10"
markerHeight="10"
refX="8"
refY="5"
orient="auto"
markerUnits="strokeWidth">
<path
d="M 1,1 L 9,5 L 1,9 Z"
fill="#ff6b6b"
id="path54" />
</marker>
<marker
id="arrowRight-3"
markerWidth="12"
markerHeight="12"
refX="9"
refY="6"
orient="auto"
markerUnits="strokeWidth">
<path
d="m 2,2 8,4 -8,4 z"
fill="#4c6ef5"
id="path48-6" />
</marker>
</defs>
<style>
@media (prefers-color-scheme: dark) {
/* Gradients */
#bgGradient stop:first-child { stop-color: #1f2937; }
#bgGradient stop:last-child { stop-color: #111827; }
#peerGradient stop:first-child { stop-color: #3b82f6; }
#peerGradient stop:last-child { stop-color: #2563eb; }
#networkGradient stop:first-child { stop-color: #10b981; }
#networkGradient stop:last-child { stop-color: #059669; }
#tunnelGradient stop:first-child { stop-color: #3b82f6; stop-opacity: 0.8; }
#tunnelGradient stop:nth-child(2) { stop-color: #2563eb; stop-opacity: 1; }
#tunnelGradient stop:last-child { stop-color: #3b82f6; stop-opacity: 0.8; }
/* White backgrounds to dark */
rect[fill="white"] { fill: #374151; }
/* Borders */
rect[stroke="#dee2e6"] { stroke: #4b5563; }
rect[stroke="#4263eb"] { stroke: #3b82f6; }
rect[stroke="#4dabf7"] { stroke: #60a5fa; }
rect[stroke="#fa5252"] { stroke: #ef4444; }
rect[stroke="#fab005"] { stroke: #f59e0b; }
/* Background colors */
rect[fill="#e7f5ff"] { fill: #1e3a8a; }
rect[fill="#fff5f5"] { fill: #7f1d1d; }
rect[fill="#fff3bf"] { fill: #78350f; }
rect[fill="#ffffff"] { fill: #374151; }
/* Text colors */
text[fill="#364fc7"] { fill: #60a5fa; }
text[fill="#2b8a3e"] { fill: #10b981; }
text[fill="#868e96"] { fill: #9ca3af; }
text[fill="#1971c2"] { fill: #60a5fa; }
text[fill="#c92a2a"] { fill: #f87171; }
text[fill="#2f9e44"] { fill: #34d399; }
text[fill="#495057"] { fill: #d1d5db; }
text[fill="#e67700"] { fill: #fbbf24; }
text[fill="#fa5252"] { fill: #f87171; }
text[fill="#4263eb"] { fill: #60a5fa; }
/* Arrows and strokes */
line[stroke="#4c6ef5"] { stroke: #60a5fa; }
path[stroke="#ff6b6b"] { stroke: #f87171; }
#arrowRight path { fill: #60a5fa; }
#arrowLeft path { fill: #60a5fa; }
#arrowRight-3 path { fill: #60a5fa; }
#keyArrow path { fill: #f87171; }
}
</style>
<line
id="traffic-arrow-right-5"
x1="690.22913"
y1="168.51242"
x2="584.96887"
y2="264.0126"
stroke="#4c6ef5"
stroke-width="2.5"
stroke-dasharray="6, 4"
marker-end="url(#arrowRight-3)"
style="display:inline;marker-end:url(#arrowRight-3);fill:none"
inkscape:label="traffic-arrow-right-5" />
<!-- Title -->
<text
id="title"
x="450"
y="30"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="22"
font-weight="800"
fill="#364fc7">Understanding WireGuard: Keys &amp; allowed-ips</text>
<!-- Peer A (Left Side) -->
<g
id="peer-a">
<!-- Network behind Peer A -->
<g
id="network-a"
filter="url(#cardShadow)">
<rect
id="network-a-bg"
x="30"
y="80"
width="180"
height="90"
rx="12"
fill="white"
stroke="#dee2e6"
stroke-width="2" />
<rect
id="network-a-header-bg"
x="30"
y="80"
width="180"
height="30"
rx="12"
fill="url(#networkGradient)" />
<rect
id="network-a-header-extension"
x="30"
y="98"
width="180"
height="12"
fill="url(#networkGradient)" />
<text
id="network-a-title"
x="120"
y="98"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="13"
font-weight="700"
fill="white">Network A</text>
<text
id="network-a-cidr"
x="120"
y="130"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="16"
font-weight="600"
fill="#2b8a3e">192.168.1.0/24</text>
<text
id="network-a-devices"
x="120"
y="155"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10"
fill="#868e96">Devices: .1, .2, .3...</text>
</g>
<!-- WireGuard Peer A -->
<g
id="wg-peer-a"
filter="url(#cardShadow)">
<rect
id="wg-peer-a-bg"
x="30"
y="200"
width="180"
height="170"
rx="12"
fill="white"
stroke="#4263eb"
stroke-width="3" />
<rect
id="wg-peer-a-header-bg"
x="30"
y="200"
width="180"
height="35"
rx="12"
fill="url(#peerGradient)" />
<rect
id="wg-peer-a-header-extension"
x="30"
y="221"
width="180"
height="14"
fill="url(#peerGradient)" />
<text
id="wg-peer-a-title"
x="120"
y="221"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="15"
font-weight="700"
fill="white">WireGuard Peer A</text>
<!-- Interface IP -->
<rect
id="wg-peer-a-interface-bg"
x="50"
y="245"
width="140"
height="22"
rx="6"
fill="#e7f5ff"
stroke="#4dabf7"
stroke-width="1" />
<text
id="wg-peer-a-interface-text"
x="120"
y="260"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="11"
font-weight="600"
fill="#1971c2">wg0: 10.0.0.1/24</text>
<!-- Own Keys -->
<rect
id="wg-peer-a-keys-bg"
x="40"
y="275"
width="160"
height="30"
rx="6"
fill="#fff5f5"
stroke="#fa5252"
stroke-width="1.5" />
<text
id="wg-peer-a-private-key"
x="120"
y="288"
text-anchor="middle"
font-family="Consolas, Monaco, 'Courier New', monospace"
font-size="9px"
font-weight="600"
fill="#c92a2a">PrivateKey: aaa...=</text>
<text
id="wg-peer-a-public-key"
x="120"
y="300"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="600"
fill="#2f9e44">PublicKey: AAA...=</text>
<!-- Peer B Config -->
<text
id="wg-peer-a-peer-config-label"
x="120"
y="320"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10"
font-weight="700"
fill="#495057">[Peer] # Peer B</text>
<rect
id="wg-peer-a-peer-config-bg"
x="40"
y="325"
width="160"
height="38"
rx="6"
fill="#fff3bf"
stroke="#fab005"
stroke-width="1.5" />
<text
id="wg-peer-a-peer-pubkey"
x="120"
y="338"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700">PublicKey = BBB...=</text>
<text
id="wg-peer-a-peer-allowed-ips-1"
x="120"
y="350"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700">allowed-ips = 10.0.0.2/32,</text>
<text
id="wg-peer-a-peer-allowed-ips-2"
x="120"
y="360"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700"> 192.168.2.0/24</text>
</g>
</g>
<!-- Peer B (Right Side) -->
<g
id="peer-b">
<!-- Network behind Peer B -->
<g
id="network-b"
filter="url(#cardShadow)">
<rect
id="network-b-bg"
x="690"
y="80"
width="180"
height="90"
rx="12"
fill="white"
stroke="#dee2e6"
stroke-width="2" />
<rect
id="network-b-header-bg"
x="690"
y="80"
width="180"
height="30"
rx="12"
fill="url(#networkGradient)" />
<rect
id="network-b-header-extension"
x="690"
y="98"
width="180"
height="12"
fill="url(#networkGradient)" />
<text
id="network-b-title"
x="780"
y="98"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="13"
font-weight="700"
fill="white">Network B</text>
<text
id="network-b-cidr"
x="780"
y="130"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="16"
font-weight="600"
fill="#2b8a3e">192.168.2.0/24</text>
<text
id="network-b-devices"
x="780"
y="155"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10"
fill="#868e96">Devices: .1, .2, .3...</text>
</g>
<!-- WireGuard Peer B -->
<g
id="wg-peer-b"
filter="url(#cardShadow)">
<rect
id="wg-peer-b-bg"
x="690"
y="200"
width="180"
height="170"
rx="12"
fill="white"
stroke="#4263eb"
stroke-width="3" />
<rect
id="wg-peer-b-header-bg"
x="690"
y="200"
width="180"
height="35"
rx="12"
fill="url(#peerGradient)" />
<rect
id="wg-peer-b-header-extension"
x="690"
y="221"
width="180"
height="14"
fill="url(#peerGradient)" />
<text
id="wg-peer-b-title"
x="780"
y="221"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="15"
font-weight="700"
fill="white">WireGuard Peer B</text>
<!-- Interface IP -->
<rect
id="wg-peer-b-interface-bg"
x="710"
y="245"
width="140"
height="22"
rx="6"
fill="#e7f5ff"
stroke="#4dabf7"
stroke-width="1" />
<text
id="wg-peer-b-interface-text"
x="780"
y="260"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="11"
font-weight="600"
fill="#1971c2">wg0: 10.0.0.2/24</text>
<!-- Own Keys -->
<rect
id="wg-peer-b-keys-bg"
x="700"
y="275"
width="160"
height="30"
rx="6"
fill="#fff5f5"
stroke="#fa5252"
stroke-width="1.5" />
<text
id="wg-peer-b-private-key"
x="780"
y="288"
text-anchor="middle"
font-family="Consolas, Monaco, 'Courier New', monospace"
font-size="9px"
font-weight="600"
fill="#c92a2a">PrivateKey: bbb...=</text>
<text
id="wg-peer-b-public-key"
x="780"
y="300"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="600"
fill="#2f9e44">PublicKey: BBB...=</text>
<!-- Peer A Config -->
<text
id="wg-peer-b-peer-config-label"
x="780"
y="320"
text-anchor="middle"
font-family="system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10"
font-weight="700"
fill="#495057">[Peer] # Peer A</text>
<rect
id="wg-peer-b-peer-config-bg"
x="700"
y="325"
width="160"
height="38"
rx="6"
fill="#fff3bf"
stroke="#fab005"
stroke-width="1.5" />
<text
id="wg-peer-b-peer-pubkey"
x="780"
y="338"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700">PublicKey = AAA...=</text>
<text
id="wg-peer-b-peer-allowed-ips-1"
x="780"
y="350"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700">allowed-ips = 10.0.0.1/32,</text>
<text
id="wg-peer-b-peer-allowed-ips-2"
x="780"
y="360"
text-anchor="middle"
font-family="'Consolas', 'Monaco', 'Courier New', monospace"
font-size="9"
font-weight="700"
fill="#e67700"> 192.168.1.0/24</text>
</g>
</g>
<!-- Key Exchange Arrows -->
<path
id="key-arrow-a-to-b"
d="m 178.05495,298.67711 q 309.54082,10.30088 544.04144,39.14333"
stroke="#ff6b6b"
stroke-width="2.45742"
stroke-dasharray="6, 4"
fill="none"
marker-end="url(#keyArrow)" />
<text
id="key-label-a"
x="362.67459"
y="320.16849"
text-anchor="middle"
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10px"
font-weight="600"
fill="#fa5252">A's public key (AAA...=)</text>
<path
id="key-arrow-b-to-a"
d="M 729.1812,299.9818 Q 415.736,360.0266 178.27753,338.01017"
stroke="#ff6b6b"
stroke-width="2.4374"
stroke-dasharray="6, 4"
fill="none"
marker-end="url(#keyArrow)" />
<text
id="key-label-b"
x="375.15118"
y="360.33688"
text-anchor="middle"
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="10px"
font-weight="600"
fill="#fa5252">B's public key (BBB...=)</text>
<!-- WireGuard Tunnel -->
<g
id="tunnel"
transform="translate(0.0587404,0.39164733)">
<line
id="tunnel-glow"
x1="210"
y1="285"
x2="690"
y2="285"
stroke="#4c6ef5"
stroke-width="10"
opacity="0.2"
filter="url(#glow)" />
<line
id="tunnel-line"
x1="210"
y1="285"
x2="690"
y2="285"
stroke="url(#tunnelGradient)"
stroke-width="5"
style="stroke:url(#tunnelGradient)" />
<!-- Tunnel label -->
<rect
id="tunnel-label-bg"
x="380"
y="270"
width="140"
height="30"
rx="8"
fill="#ffffff"
stroke="#4263eb"
stroke-width="2"
filter="url(#cardShadow)" />
<text
id="tunnel-label-text"
x="450"
y="290"
text-anchor="middle"
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="12px"
font-weight="700"
fill="#4263eb">WireGuard Tunnel</text>
</g>
<!-- Explanation Box -->
<!-- Traffic Flow Example -->
<g
id="traffic-left"
transform="matrix(1.0191745,0,0,1.0648706,-3.9974789,-10.979528)">
<line
id="traffic-arrow-left"
x1="210"
y1="170"
x2="320"
y2="260"
stroke="#4c6ef5"
stroke-width="2.5"
stroke-dasharray="6, 4"
marker-end="url(#arrowRight)" />
<text
id="traffic-label-left"
x="290"
y="215"
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="9px"
font-weight="600"
fill="#4263eb">to 192.168.2.x</text>
</g>
<text
id="traffic-label-right"
x="583.14978"
y="201.57195"
font-family="system-ui, '-apple-system', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"
font-size="9px"
font-weight="600"
fill="#4263eb">to 192.168.1.x</text>
<path
style="fill:none"
d="m 585.61735,261.45164 c -1.59298,2.54412 -1.30788,10.31284 2.71904,6.28562"
id="path1111" />
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

-445
View File
@@ -1,445 +0,0 @@
# IP Address Configuration
This section details IP Addresses And Other Per-Interface IP settings.
Infix support several network interface types, each can be assigned one
or more IP addresses, both IPv4 and IPv6 are supported. (There is no
concept of a "primary" address.)
![IP on top of network interface examples](img/ip-iface-examples.svg)
## IPv4 Address Assignment
Multiple address assignment methods are available:
| **Type** | **Yang Model** | **Description** |
|:---------- |:----------------- |:-------------------------------------------------------------- |
| static | ietf-ip | Static assignment of IPv4 address, e.g., *10.0.1.1/24* |
| link-local | infix-ip | Auto-assignment of IPv4 address in 169.254.x.x/16 range |
| dhcp | infix-dhcp-client | Assignment of IPv4 address by DHCP server, e.g., *10.0.1.1/24* |
> [!NOTE]
> The DHCP address method is only available for *LAN* interfaces
> (Ethernet, virtual Ethernet (veth), bridge, link aggregates, etc.)
Supported DHCP (request) options, configurability (Cfg) and defaults,
are listed below. Configurable options can be disabled on a per client
interface basis, some options, like `clientid` and option 81, are
possible to set the value of as well.
| **Opt** | **Name** | **Cfg** | **Description** |
|---------|-----------------------------|---------|-----------------------------------------------------|
| 1 | `netmask` | No | Request IP address and netmask |
| 3 | `router` | Yes | Default route(s), see also option 121 and 249 |
| 6 | `dns-server` | Yes | DNS server(s), static ones take precedence |
| 12 | `hostname` | Yes | DHCP cannot set hostname, only for informing server |
| 15 | `domain` | Yes | Default domain name, for name resolution |
| 28 | `broadcast` | Yes | Broadcast address, calculated if disabled |
| 42 | `ntp-server` | Yes | NTP server(s), static ones take precedence |
| 50 | `address` | Yes | Request (previously cached) address |
| 61 | `client-id` | Yes | Default MAC address (and option 12) |
| 81 | `fqdn` | Yes | Similar to option 12, request FQDN update in DNS |
| 119 | `search` | Yes | Request domain search list |
| 121 | `classless-static-route` | Yes | Classless static routes |
| 249 | `ms-classless-static-route` | Yes | Microsoft static route, same as option 121 |
| | | | |
**Default:** `router`, `dns-server`, `domain`, `broadcast`, `ntp-server`, `search`,
`address`, `classless-static-route`, `ms-classless-static-route`
When configuring a DHCP client, ensure that the NTP client is enabled
for the `ntp-server` DHCP option to be processed correctly. If the NTP
client is not enabled, any NTP servers provided by the DHCP server will
be ignored. For details on how to enable the NTP client, see the [NTP
Client Configuration](system.md#ntp-client-configuration) section.
> [!IMPORTANT]
> Per [RFC3442][1], if the DHCP server returns both a Classless Static
> Routes option (121) and Router option (3), the DHCP client *must*
> ignore the latter.
## IPv6 Address Assignment
Multiple address assignment methods are available:
| **Type** | **Yang Model** | **Description** |
|:---------------- |:-------------------- |:------------------------------------------------------------------------------------------------------------------------------------------------- |
| static | ietf-ip | Static assignment of IPv6 address, e.g., *2001:db8:0:1::1/64* |
| link-local | ietf-ip[^1] | (RFC4862) Auto-configured link-local IPv6 address (*fe80::0* prefix + interface identifier, e.g., *fe80::ccd2:82ff:fe52:728b/64*) |
| global auto-conf | ietf-ip | (RFC4862) Auto-configured (stateless) global IPv6 address (prefix from router + interface identifier, e.g., *2001:db8:0:1:ccd2:82ff:fe52:728b/64* |
| dhcp | infix-dhcpv6-client | Assignment of IPv6 address by DHCPv6 server, e.g., *2001:db8::42/128* |
Both for *link-local* and *global auto-configuration*, it is possible
to auto-configure using a random suffix instead of the interface
identifier.
> [!NOTE]
> The DHCPv6 address method is only available for *LAN* interfaces
> (Ethernet, virtual Ethernet (veth), bridge, link aggregates, etc.)
Supported DHCPv6 (request) options, configurability (Cfg) and defaults,
are listed below. Configurable options can be disabled on a per client
interface basis, some options, like `client-id` and `client-fqdn`, are
possible to set the value of as well.
| **Opt** | **Name** | **Cfg** | **Description** |
|---------|----------------------------|---------|--------------------------------------------------------|
| 1 | `client-id` | Yes | Client identifier (DUID), auto-generated by default |
| 2 | `server-id` | Yes | Server identifier (DUID) |
| 23 | `dns-server` | Yes | DNS recursive name servers, static ones take precedence|
| 24 | `domain-search` | Yes | Domain search list |
| 25 | `ia-pd` | Yes | Prefix delegation for downstream networks |
| 31 | `sntp-server` | Yes | Simple Network Time Protocol servers |
| 32 | `information-refresh-time` | Yes | Refresh time for stateless DHCPv6 |
| 39 | `client-fqdn` | Yes | Client FQDN, request DNS update from server |
| 56 | `ntp-server` | Yes | NTP time servers, static ones take precedence |
| | | | |
**Default:** `dns-server`, `domain-search`, `ntp-server`
DHCPv6 supports both **stateful** (address assignment) and **stateless**
(information-only) modes:
- **Stateful DHCPv6**: The server assigns IPv6 addresses to clients. This is
the default mode when enabling the DHCPv6 client.
- **Stateless DHCPv6**: Used with SLAAC (Stateless Address Autoconfiguration)
when only configuration information (DNS, NTP, etc.) is needed. Enable with
the `information-only` setting.
When configuring a DHCPv6 client, ensure that the NTP client is enabled
for the `ntp-server` DHCPv6 option to be processed correctly. If the
NTP client is not enabled, any NTP servers provided by the DHCPv6 server
will be ignored. For details on how to enable the NTP client, see the
[NTP Client Configuration](system.md#ntp-client-configuration) section.
## Examples
![Switch example (eth0 and lo)](img/ip-address-example-switch.svg)
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
To illustrate IP address configuration, the examples below uses a
switch with a single Ethernet interface (eth0) and a loopback
interface (lo). As shown above, these examples assume *eth0* has an
IPv6 link-local address and *lo* has static IPv4 and IPv6 addresses by
default.
### Static and link-local IPv4 addresses
![Setting static IPv4 (and link-local IPv4)](img/ip-address-example-ipv4-static.svg)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv4</b>
admin@example:/config/interface/eth0/ipv4/> <b>set address 10.0.1.1 prefix-length 24</b>
admin@example:/config/interface/eth0/ipv4/> <b>set autoconf</b>
admin@example:/config/interface/eth0/ipv4/> <b>diff</b>
+interfaces {
+ interface eth0 {
+ ipv4 {
+ address 10.0.1.1 {
+ prefix-length 24;
+ }
+ autoconf;
+ }
+ }
+}
admin@example:/config/interface/eth0/ipv4/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv4 169.254.1.3/16 (random)
ipv4 10.0.1.1/24 (static)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
As shown, the link-local IPv4 address is configured with `set autoconf`.
The presence of the `autoconf` container enables IPv4 link-local address
assignment. The resulting address (169.254.1.3/16) is of type *random*
([ietf-ip.yang][2]).
The IPv4LL client also supports a `request-address` setting which can be
used to "seed" the client's starting address. If the address is free it
will be used, otherwise it falls back to the default algorithm.
<pre class="cli"><code>admin@example:/config/interface/eth0/ipv4/> <b>edit autoconf</b>
admin@example:/config/interface/eth0/ipv4/autoconf/> <b>set request-address 169.254.1.2</b>
admin@example:/config/interface/eth0/ipv4/autoconf/> <b>leave</b>
</code></pre>
### Use of DHCP for IPv4 address assignment
![Using DHCP for IPv4 address assignment](img/ip-address-example-ipv4-dhcp.svg)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv4</b>
admin@example:/config/interface/eth0/ipv4/> <b>set dhcp</b>
admin@example:/config/interface/eth0/ipv4/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv4 10.1.2.100/24 (dhcp)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
The resulting address (10.1.2.100/24) is of type *dhcp*.
To configure DHCP client options, such as sending a specific hostname to the
server, you can specify options with values:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv4 dhcp</b>
admin@example:/config/interface/eth0/ipv4/dhcp/> <b>set option hostname value myhost</b>
admin@example:/config/interface/eth0/ipv4/dhcp/> <b>show</b>
option hostname {
value myhost;
}
admin@example:/config/interface/eth0/ipv4/dhcp/> <b>leave</b>
admin@example:/>
</code></pre>
> [!TIP]
> The special value `auto` can be used with the hostname option to
> automatically use the configured system hostname.
Other useful DHCP options include:
- `client-id` - Send a specific client identifier to the server
- `route-preference` - Set the administrative distance for DHCP-learned routes (default: 5)
For advanced usage with vendor-specific options, see the YANG model.
### Use of DHCPv6 for IPv6 address assignment
![Using DHCPv6 for IPv6 address assignment](img/ip-address-example-ipv6-dhcp.svg)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set dhcp</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interface</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8::42/128 (dhcp)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
The resulting address (2001:db8::42/128) is of type *dhcp*.
To configure DHCPv6 client options, such as requesting prefix delegation
for downstream networks, you can specify options:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6 dhcp</b>
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>set option ia-pd</b>
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>set option dns-server</b>
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>show</b>
option dns-server;
option ia-pd;
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>leave</b>
admin@example:/>
</code></pre>
For stateless DHCPv6 (used with SLAAC to get only configuration information):
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6 dhcp</b>
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>set information-only true</b>
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>show</b>
information-only true;
option dns-server;
option domain-search;
admin@example:/config/interface/eth0/ipv6/dhcp/> <b>leave</b>
admin@example:/>
</code></pre>
Other useful DHCPv6 options include:
- `duid` - Set a specific DHCPv6 Unique Identifier (auto-generated by default)
- `client-fqdn` - Request the server to update DNS records with client's FQDN
- `route-preference` - Set the administrative distance for DHCPv6-learned routes (default: 5)
For advanced usage with vendor-specific options, see the YANG model.
### Disabling IPv6 link-local address(es)
The (only) way to disable IPv6 link-local addresses is by disabling IPv6
on the interface.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set enabled false</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
### Static IPv6 address
![Setting static IPv6](img/ip-address-example-ipv6-static.svg)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set address 2001:db8::1 prefix-length 64</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8::1/64 (static)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
### Stateless Auto-configuration of Global IPv6 Address
![Auto-configuration of global IPv6](img/ip-address-example-ipv6-auto-global.svg)
Stateless address auto-configuration of global addresses is enabled by
default. The address is formed by concatenating the network prefix
advertised by the router (here 2001:db8:0:1::0/64) and the interface
identifier. The resulting address is of type *link-layer*, as it is
formed based on the interface identifier ([ietf-ip.yang][2]).
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:0:ff:fe00:0/64 (link-layer)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
Disabling auto-configuration of global IPv6 addresses can be done as shown
below.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set autoconf create-global-addresses false</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
### Random Link Identifiers for IPv6 Stateless Autoconfiguration
![Auto-configuration of global IPv6](img/ip-address-example-ipv6-auto-global.svg)
By default, the auto-configured link-local and global IPv6 addresses
are formed from a link-identifier based on the MAC address.
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:0:ff:fe00:0/64 (link-layer)
ipv6 fe80::ff:fe00:0/64 (link-layer)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
To avoid revealing identity information in the IPv6 address, it is
possible to specify use of a random identifier ([ietf-ip.yang][2] and
[RFC8981][3]).
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface eth0 ipv6</b>
admin@example:/config/interface/eth0/ipv6/> <b>set autoconf create-temporary-addresses true</b>
admin@example:/config/interface/eth0/ipv6/> <b>leave</b>
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
eth0 ethernet UP 02:00:00:00:00:00
ipv6 2001:db8:0:1:b705:8374:638e:74a8/64 (random)
ipv6 fe80::ad3d:b274:885a:9ffb/64 (random)
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
admin@example:/>
</code></pre>
Both the link-local address (fe80::) and the global address (2001:)
have changed type to *random*.
## IPv4 forwarding
To be able to route (static or dynamic) on the interface it is
required to enable forwarding. This setting controls if packets
received on this interface can be forwarded.
<pre class="cli"><code>admin@example:/config/> <b>edit interface eth0</b>
admin@example:/config/interface/eth0/> <b>set ipv4 forwarding</b>
admin@example:/config/interface/eth0/> <b>leave</b>
admin@example:/>
</code></pre>
## IPv6 forwarding
Due to how the Linux kernel manages IPv6 forwarding, we can not fully
control it per interface via this setting like how IPv4 works. Instead,
IPv6 forwarding is globally enabled when at least one interface enable
forwarding, otherwise it is disabled.
The following table shows the system IPv6 features that the `forwarding`
setting control when it is *Enabled* or *Disabled:
| **IPv6 Feature** | **Enabled** | **Disabled** |
|:-----------------------------------------|:------------|:-------------|
| IsRouter set in Neighbour Advertisements | Yes | No |
| Transmit Router Solicitations | No | Yes |
| Router Advertisements are ignored | Yes | Yes |
| Accept Redirects | No | Yes |
<pre class="cli"><code>admin@example:/config/> <b>edit interface eth0</b>
admin@example:/config/interface/eth0/> <b>set ipv6 forwarding</b>
admin@example:/config/interface/eth0/> <b>leave</b>
admin@example:/>
</code></pre>
[1]: https://www.rfc-editor.org/rfc/rfc3442
[2]: https://www.rfc-editor.org/rfc/rfc8344
[3]: https://www.rfc-editor.org/rfc/rfc8981
[^1]: Link-local IPv6 addresses are implicitly enabled when enabling
IPv6. IPv6 can be enabled/disabled per interface in the
[ietf-ip][2] YANG model.
-245
View File
@@ -1,245 +0,0 @@
# Link Aggregation
A link aggregate, or *lag*, allows multiple physical interfaces to be
combined into a single logical interface, providing increased bandwidth
(in some cases) and redundancy (primarily). Two modes of qualifying lag
member ports are available:
1. **static**: Active members selected based on link status (carrier)
2. **lacp:** IEEE 802.3ad Link Aggregation Control Protocol
In LACP mode, LACPDUs are exchanged by the link partners to qualify each
lag member, while in static mode only carrier is used. This additional
exchange in LACP ensures traffic can be forwarded in both directions.
Traffic distribution, for both modes, across the active lag member ports
is determined by the hash policy[^1]. It uses an XOR of the source,
destination MAC addresses and the EtherType field. This, IEEE
802.3ad-compliant, algorithm will place all traffic to a particular
network peer on the same link. Meaning there is no increased bandwidth
for communication between two specific devices.
> [!TIP]
> Similar to other interface types, naming your interface `lagN`, where
> `N` is a number, allows the CLI to automatically infer the interface
> type as LAG.
## Basic Configuration
Creating a link aggregate interface and adding member ports:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface lag0</b>
admin@example:/config/interface/lag0/> <b>set lag mode static</b>
admin@example:/config/interface/lag0/> <b>end</b>
admin@example:/config/> <b>set interface eth7 lag-port lag lag0</b>
admin@example:/config/> <b>set interface eth8 lag-port lag lag0</b>
admin@example:/config/> <b>leave</b>
</code></pre>
A static lag responds only to link (carrier) changes of member ports.
E.g., in this example egressing traffic is continuously distributed over
the two links until link down on one link is detected, triggering all
traffic to be steered to the sole remaining link.
## LACP Configuration
LACP mode provides dynamic negotiation of the link aggregate. Key
settings include:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface lag0</b>
admin@example:/config/interface/lag0/> <b>set lag mode lacp</b>
admin@example:/config/interface/lag0/> <b>set lag lacp mode passive</b>
admin@example:/config/interface/lag0/> <b>set lag lacp rate fast</b>
admin@example:/config/interface/lag0/> <b>set lag lacp system-priority 100</b>
</code></pre>
LACP mode supports two operational modes:
- **active:** Initiates negotiation by sending LACPDUs (default)
- **passive:** Waits for peer to initiate negotiation
> [!NOTE]
> At least one end of the link must be in active mode for negotiation to occur.
The LACP rate setting controls protocol timing:
- **slow:** LACPDUs sent every 30 seconds, with 90 second timeout (default)
- **fast:** LACPDUs sent every second, with 3 second timeout
## Link Flapping
To protect against link flapping, debounce timers can be configured to
delay link qualification. Usually only the `up` delay is needed:
<pre class="cli"><code>admin@example:/config/interface/lag0/lag/link-monitor/> <b>edit debounce</b>
admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>set up 500</b>
admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>set down 200</b>
</code></pre>
## Operational Status, Overview
Like other interfaces, link aggregates are also available in the general
interfaces overview in the CLI admin-exec context. Here is the above
static mode aggregate:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
.
.
.
lag0 lag UP static: balance-xor, hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE
└ eth8 lag ACTIVE
</code></pre>
Same aggregate, but in LACP mode:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
.
.
.
lag0 lag UP lacp: active, rate: fast (1s), hash: layer2
│ ethernet UP 00:a0:85:00:02:00
├ eth7 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
└ eth8 lag ACTIVE active, short_timeout, aggregating, in_sync, collecting, distributing
</code></pre>
## Operational Status, Detail
In addition to basic status shown in the interface overview, detailed
LAG status can be inspected:
<pre class="cli"><code>admin@example:/> <b>show interface lag0</b>
name : lag0
index : 25
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : static
lag type : balance-xor
lag hash : layer2
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 0
out-octets : 2142
</code></pre>
Same aggregate, but in LACP mode:
<pre class="cli"><code>admin@example:/> <b>show interface lag0</b>
name : lag0
index : 24
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag mode : lacp
lag hash : layer2
lacp mode : active
lacp rate : fast (1s)
lacp aggregate id : 1
lacp system priority: 65535
lacp actor key : 9
lacp partner key : 9
lacp partner mac : 00:a0:85:00:03:00
link debounce up : 0 msec
link debounce down : 0 msec
ipv4 addresses :
ipv6 addresses :
in-octets : 100892
out-octets : 111776
</code></pre>
Member ports provide additional status information:
- Link failure counter: number of detected link failures
- LACP state flags: various states of LACP negotiation:
- `active`: port is actively sending LACPDUs
- `short_timeout`: using fast rate (1s) vs. slow rate (30s)
- `aggregating`: port is allowed to aggregate in this LAG
- `in_sync`: port is synchronized with partner
- `collecting`: port is allowed to receive traffic
- `distributing`: port is allowed to send traffic
- `defaulted`: using default partner info (partner not responding)
- `expired`: partner info has expired (no LACPDUs received)
- Aggregator ID: unique identifier for this LAG group
- Actor state: LACP state flags for this port (local)
- Partner state: LACP state flags from the remote port
Example member port status:
<pre class="cli"><code>admin@example:/> <b>show interface eth7</b>
name : eth7
index : 8
mtu : 1500
operational status : up
physical address : 00:a0:85:00:02:00
lag member : lag0
lag member state : active
lacp aggregate id : 1
lacp actor state : active, short_timeout, aggregating, in_sync, collecting, distributing
lacp partner state : active, short_timeout, aggregating, in_sync, collecting, distributing
link failure count : 0
ipv4 addresses :
ipv6 addresses :
in-octets : 473244
out-octets : 499037
</code></pre>
## Example: Switch Uplink with LACP
LACP mode provides the most robust operation, automatically negotiating
the link aggregate and detecting configuration mismatches.
A common use case is connecting a switch to an upstream device:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface lag0</b>
admin@example:/config/interface/lag0/> <b>set lag mode lacp</b>
</code></pre>
Enable fast LACP for quicker fail-over:
<pre class="cli"><code>admin@example:/config/interface/lag0/> <b>set lag lacp rate fast</b>
</code></pre>
Add uplink ports
<pre class="cli"><code>admin@example:/config/interface/lag0/> <b>end</b>
admin@example:/config/> <b>set interface eth7 lag-port lag lag0</b>
admin@example:/config/> <b>set interface eth8 lag-port lag lag0</b>
</code></pre>
Enable protection against "link flapping".
<pre class="cli"><code>admin@example:/config/interface/lag0/> <b>edit lag link-monitor</b>
admin@example:/config/interface/lag0/lag/link-monitor/> <b>edit debounce</b>
admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>set up 500</b>
admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>set down 200</b>
admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>top</b>
</code></pre>
Add to bridge for switching
<pre class="cli"><code>admin@example:/config/interface/lag0/lag/link-monitor/debounce/> <b>end</b>
admin@example:/config/> <b>set interface lag0 bridge-port bridge br0</b>
admin@example:/config/> <b>leave</b>
</code></pre>
[^1]: `(source MAC XOR destination MAC XOR EtherType) MODULO num_links`
+48 -40
View File
@@ -9,20 +9,22 @@ as NETCONF, RESTCONF, and CLI via SSH or Console.
An SSH server (SSHv2) is provided for remote management. It can be
enabled/disabled as shown below.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit ssh</b>
admin@example:/config/ssh/> <b>set enabled</b>
```
admin@example:/> configure
admin@example:/config/> edit ssh
admin@example:/config/ssh/> set enabled
admin@example:/config/ssh/>
</code></pre>
```
By default the SSH server accepts connections to port 22 on all its IP
addresses, but this can be adjusted using the `listen` command. To
make the server (only) listen for incoming connections to IP address
_192.168.1.1_ and port _12345_ the following commands can be used.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit ssh</b>
admin@example:/config/ssh/> <b>show</b>
```
admin@example:/> configure
admin@example:/config/> edit ssh
admin@example:/config/ssh/> show
enabled true;
hostkey genkey;
listen ipv4 {
@@ -33,12 +35,12 @@ listen ipv6 {
address ::;
port 22;
}
admin@example:/config/ssh/> <b>no listen ipv6</b>
admin@example:/config/ssh/> <b>edit listen ipv4</b>
admin@example:/config/ssh/listen/ipv4/> <b>set address 192.168.1.1</b>
admin@example:/config/ssh/listen/ipv4/> <b>set port 12345</b>
admin@example:/config/ssh/> no listen ipv6
admin@example:/config/ssh/> edit listen ipv4
admin@example:/config/ssh/listen/ipv4/> set address 192.168.1.1
admin@example:/config/ssh/listen/ipv4/> set port 12345
admin@example:/config/ssh/listen/ipv4/>
</code></pre>
```
The default SSH hostkey is generated on first boot and is used in both
SSH and NETCONF (SSH transport). Custom keys can be added to the
@@ -60,10 +62,9 @@ created by OpenSSL.
After the key has been stored in the keystore and given the name
_mykey_ it can be added to SSH configuration:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit ssh</b>
admin@example:/config/ssh/> <b>set hostkey mykey</b>
</code></pre>
admin@example:/> configure
admin@example:/config/> edit ssh
admin@example:/config/ssh/> set hostkey mykey
## Console Port
@@ -77,8 +78,9 @@ connected to the console port of the device. The serial port is
typically setup to run at 115200 baud, 8N1.
<pre class="cli"><code>Infix OS — Immutable.Friendly.Secure v24.11.1 (ttyS0)
example login: <b>admin</b>
```
Infix OS — Immutable.Friendly.Secure v24.11.1 (ttyS0)
example login: admin
Password:
.-------.
| . . | Infix OS — Immutable.Friendly.Secure
@@ -88,24 +90,26 @@ Password:
Run the command 'cli' for interactive OAM
admin@example:~$
</code></pre>
```
The `resize` command can be used to update terminal settings to the
size of your terminal window.
<pre class="cli"><code>admin@example:~$ <b>resize</b>
```
admin@example:~$ resize
COLUMNS=115;LINES=59;export COLUMNS LINES;
admin@example:~$
</code></pre>
```
CLI can be entered from shell in the same way as for SSH.
<pre class="cli"><code>admin@example:~$ <b>cli</b>
```
admin@example:~$ cli
See the 'help' command for an introduction to the system
admin@example:/> <b>show interfaces</b>
<span class="header">INTERFACE PROTOCOL STATE DATA </span>
admin@example:/> show interfaces
INTERFACE PROTOCOL STATE DATA
lo ethernet UP 00:00:00:00:00:00
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
@@ -113,7 +117,7 @@ e1 ethernet LOWER-DOWN 00:53:00:06:03:01
e2 ethernet LOWER-DOWN 00:53:00:06:03:02
...
admin@example:/>
</code></pre>
```
## Web, Web-console and RESTCONF
@@ -128,25 +132,27 @@ There is also a *Netbrowse* Web service presenting information about
the unit's neighbors, collected via mDNS (see
[Discovery](discovery.md) for more details).
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit web</b>
admin@example:/config/web/> <b>help</b>
```
admin@example:/> configure
admin@example:/config/> edit web
admin@example:/config/web/> help
enabled Enable or disable on all web services.
console Web console interface.
netbrowse mDNS Network Browser.
restconf IETF RESTCONF Server.
admin@example:/config/web/>
</code></pre>
```
### Enable/disable Web Service and Server
The Web service can be enabled as shown below.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit web</b>
admin@example:/config/web/> <b>set enabled</b>
admin@example:/config/web/>
</code></pre>
```
admin@example:/> configure
admin@example:/config/> edit web
admin@example:/config/web/> set enabled
admin@example:/config/web/>
```
Enabling the Web service implies that a Web server is
enabled. Currently this Web server provides generic Infix information,
@@ -166,10 +172,11 @@ The Web console has its own enable/disable setting, but will only be
activated if the Web service is enabled. The example below shows how
to disable the Web console.
<pre class="cli"><code>admin@example:/config/web/> <b>edit console</b>
admin@example:/config/web/console/> <b>no enabled</b>
```
admin@example:/config/web/> edit console
admin@example:/config/web/console/> no enabled
admin@example:/config/web/console/>
</code></pre>
```
### Enable/disable RESTCONF Service
@@ -181,10 +188,11 @@ The RESTCONF service has its own enable/disable setting, but will
only be activated if the Web service is enabled. The example below
shows how to disable the RESTCONF service.
<pre class="cli"><code>admin@example:/config/web/> <b>edit restconf</b>
admin@example:/config/web/restconf/> <b>no enabled</b>
```
admin@example:/config/web/> edit restconf
admin@example:/config/web/restconf/> no enabled
admin@example:/config/web/restconf/>
</code></pre>
```
## System Upgrade
-640
View File
@@ -1,640 +0,0 @@
# Network Access Control Model (NACM)
NETCONF Access Control Model ([RFC 8341][1]) provides fine-grained access
control for YANG data models. NACM controls who can read, write, and
execute operations on specific parts of the configuration and operational
state.
This document provides technical details about how NACM works, how rules
are evaluated, and best practices for creating custom access control
policies.
> [!TIP]
> For a practical introduction to user management and the built-in user
> levels (admin, operator, guest), see the [Multiple Users][2] section
> in the System Configuration guide.
## TL;DR - The Factory Defaults Work
**You don't need to understand NACM to use the system securely.**
The factory configuration implements a "permit by default, deny sensitive
items" policy that provides:
- **Immediate usability** - Operators can configure the entire system
without custom NACM rules
- **Automatic security** - Passwords, cryptographic keys, and dangerous
operations are protected out-of-the-box
- **Future-proof design** - New features work immediately without NACM
updates
The three built-in user levels (admin, operator, guest) cover most use
cases. Only read on if you need to create custom access control policies.
## Overview
NACM provides three types of access control:
- **Data node access** - Control read/write access to configuration and state
- **Operation access** - Control execution of RPCs (remote procedure calls)
- **Notification access** - Control subscription to event notifications (not covered here)
Access is controlled through:
1. **Global defaults** - Default permissions for read/write/exec
2. **YANG-level annotations** - Security markers in YANG modules (see below)
3. **NACM rules** - Explicit permit/deny rules organized in rule-lists
## Rule Evaluation
NACM rules are evaluated in a specific order:
1. **Rule-lists are processed sequentially** in the order they appear in the configuration
2. **Within each rule-list**, rules are evaluated sequentially
3. **First matching rule wins** - no further rules are evaluated
4. **If no rule matches**, global defaults apply (read-default, write-default, exec-default)
5. **YANG annotations override everything** - `nacm:default-deny-all` in a YANG module requires an explicit permit rule regardless of global defaults
### Example Rule Evaluation
Given this configuration:
```json
{
"read-default": "permit",
"write-default": "permit",
"rule-list": [
{
"name": "operator-acl",
"group": ["operator"],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"access-operations": "exec",
"action": "permit"
}
]
},
{
"name": "default-deny-all",
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
```
When operator user "jacky" tries to:
- **Read password**: Matches "deny-passwords" → **DENIED**
- **Write interface config**: No match, uses write-default → **PERMITTED** (write-default=permit)
- **Write hostname**: No match, uses write-default → **PERMITTED** (write-default=permit)
- **Reboot system**: Matches "permit-system-rpcs" → **PERMITTED** (overrides `nacm:default-deny-all`)
## Global Defaults
NACM has three global defaults that apply when no rule matches:
```json
{
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit"
}
```
**Factory configuration defaults:**
- `read-default: "permit"` - Users can read configuration and state by default
- `write-default: "permit"` - Users can modify configuration by default
- `exec-default: "permit"` - Users can execute RPCs by default
This permit-by-default approach, combined with targeted denials for
sensitive items (passwords, cryptographic keys), provides a balance
between usability and security. It also makes the system "future proof" -
when new YANG modules are added, operators can immediately configure them
without updating NACM rules.
> [!IMPORTANT]
> YANG modules with `nacm:default-deny-all` or `nacm:default-deny-write`
> annotations override these global defaults. You must create explicit
> permit rules for those operations.
## Module-Name vs Path
NACM rules can match operations using either `module-name` or `path`.
The following sub-sections provide detailed information and examples of
both.
### Module-Name Matching
Matches all nodes **defined** in a specific YANG module:
```json
{
"name": "permit-keystore",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "permit"
}
```
This permits all operations on data **defined** in ietf-keystore, but does
NOT cover augments from other modules.
**Example:** The `/interfaces/interface/ipv4/address` path:
- Interface is defined in `ietf-interfaces`
- IPv4 config is defined in `ietf-ip` (augments ietf-interfaces)
- A rule with `module-name: "ietf-interfaces"` does NOT cover ipv4/address
### Path Matching
Matches a specific data tree path and **all nodes under it**, including
augments from other modules:
```json
{
"name": "permit-network-config",
"path": "/ietf-interfaces:interfaces/interface",
"access-operations": "*",
"action": "permit"
}
```
This permits operations on `/interfaces/interface` **and all child nodes**,
including augments like:
- `/interfaces/interface/ipv4` (from ietf-ip)
- `/interfaces/interface/ipv6` (from ietf-ip)
- `/interfaces/interface/bridge-port` (from infix-interfaces)
**Path syntax:**
- When used **with** module-name: Path is module-relative (no prefix)
```json
"module-name": "ietf-system",
"path": "/system/authentication/user/password"
```
- When used **without** module-name: Path must include module prefix
```json
"path": "/ietf-system:system/authentication/user/password"
```
> [!TIP] Use path-based rules
> When you want to permit/deny access to a configuration subtree
> including all augments, e.g., all IP settings below
> `/ietf-interfaces:interfaces/`. This is more flexible and requires
> less maintenance as new features are added.
## YANG-Level Annotations
Many YANG modules include NACM annotations that provide baseline security:
### nacm:default-deny-all
Requires an explicit permit rule, regardless of global defaults:
```yang
rpc system-restart {
nacm:default-deny-all;
description "Restart the system";
}
```
Even with `exec-default: "permit"`, users need an explicit permit rule to
execute system-restart.
### nacm:default-deny-write
Write operations require an explicit permit rule:
```yang
container authentication {
nacm:default-deny-write;
description "User authentication configuration";
}
```
Even with `write-default: "permit"`, users need an explicit permit rule to
modify authentication settings.
### Protected Operations
The following are protected by YANG annotations and require explicit permits:
**RPC Operations:**
- `ietf-system:system-restart` ([ietf-system][3])
- `ietf-system:system-shutdown` ([ietf-system][3])
- `ietf-system:set-current-datetime` ([ietf-system][3])
- `infix-factory-default:factory-default`
- `ietf-factory-default:factory-reset` ([RFC 8808][4])
- `infix-system-software:install-bundle`
- `infix-system-software:set-boot-order`
**Data Containers:**
- `/system/authentication` (`nacm:default-deny-write`, [ietf-system][3])
- `/nacm` (`nacm:default-deny-all`, [RFC 8341][1])
- Routing protocol key chains ([ietf-key-chain][5])
- RADIUS shared secrets ([ietf-system][3])
- TLS client/server credentials ([ietf-tls-client][6])
This provides defense-in-depth - even if NACM rules are misconfigured, these
critical operations remain protected.
## Access Operations
NACM supports the following access operations:
- `create` - Create new data nodes
- `read` - Read existing data nodes
- `update` - Modify existing data nodes
- `delete` - Delete data nodes
- `exec` - Execute RPC operations
- `*` - All operations (wildcard)
**Common combinations:**
- `"create update delete"` - All write operations
- `"*"` - Everything (read, write, execute)
- `"read"` - Read-only access
## Rule-List Groups
Each rule-list applies to one or more user groups:
```json
{
"name": "operator-acl",
"group": ["operator"],
"rule": [...]
}
```
**Special group names:**
- `"*"` - Matches all users (including those not in any NACM group)
**Evaluation:**
A user can be in multiple NACM groups. All rule-lists matching the user's
groups are evaluated in order until a matching rule is found.
## Example: Factory Configuration
The factory configuration uses a "permit by default, deny sensitive items"
approach. This design is "future proof" - when new YANG modules are added,
operators can immediately configure them without updating NACM rules.
```json
{
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{"name": "admin", "user-name": ["admin"]},
{"name": "operator", "user-name": []},
{"name": "guest", "user-name": []}
]
},
"rule-list": [
{
"name": "admin-acl",
"group": ["admin"],
"rule": [
{
"name": "permit-all",
"module-name": "*",
"access-operations": "*",
"action": "permit",
"comment": "Admin has full unrestricted access"
}
]
},
{
"name": "operator-acl",
"group": ["operator"],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time"
}
]
},
{
"name": "guest-acl",
"group": ["guest"],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests can only read, not modify or execute"
}
]
},
{
"name": "default-deny-all",
"group": ["*"],
"rule": [
{
"name": "deny-password-access",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes"
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys"
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store"
}
]
}
]
}
}
```
**Key design decisions:**
1. **Permit by default** - `write-default: permit` allows operators to configure any module
2. **Minimal operator rules** - Only one rule to permit system RPCs (reboot, set time)
3. **Future proof** - New YANG modules automatically configurable by operators
4. **Targeted denials** - Only sensitive items (passwords, keys) are explicitly denied
5. **Global denials** - Password/keystore/truststore denied for everyone via group "*"
6. **YANG annotations** - Sensitive operations (factory-reset, software upgrades) still protected by `nacm:default-deny-all` in YANG modules
**Effective permissions by group:**
| Group | Read | Write | Exec | Exceptions |
|----------|------|-------|------|-----------------------------------------------|
| admin | All | All | All | None |
| operator | All | All | All | Cannot access passwords, keystore, truststore |
| guest | All | None | None | Read-only access |
## Common Patterns
### Permit-by-Default
The factory default approach - allow everything except sensitive items:
```json
{
"write-default": "permit",
"exec-default": "permit",
"rule-list": [
{
"name": "admin-acl",
"group": ["admin"],
"rule": [
{
"name": "permit-all",
"module-name": "*",
"access-operations": "*",
"action": "permit"
}
]
},
{
"name": "global-denials",
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
```
This approach is "future proof" - new YANG modules are automatically
accessible without rule updates. Admins bypass the global denials
because their `permit-all` rule is evaluated first.
### Deny-by-Default
More restrictive approach - deny everything except what is explicitly
allowed:
```json
{
"write-default": "deny",
"exec-default": "deny",
"rule-list": [
{
"group": ["limited-user"],
"rule": [
{
"name": "permit-interface-config",
"path": "/ietf-interfaces:interfaces/interface",
"access-operations": "create update delete",
"action": "permit"
}
]
}
]
}
```
> [!NOTE]
> This requires updating NACM rules whenever new features are added.
### Global Restrictions
Deny access to sensitive data for all users (except admins with permit-all):
```json
{
"rule-list": [
{
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
```
## Debugging NACM
### Viewing Effective Permissions
Check what NACM groups a user belongs to:
<pre class="cli"><code>admin@example:/> <b>show nacm</b>
enabled : yes
default read access : permit
default write access : permit
default exec access : permit
denied operations : 0
denied data writes : 0
denied notifications : 0
┌──────────┬─────────┬─────────┬─────────┐
│ GROUP │ READ │ WRITE │ EXEC │
├──────────┼─────────┼─────────┼─────────┤
│ admin │ ✓ │ ✓ │ ✓ │
│ operator │ ⚠ │ ⚠ │ ⚠ │
│ guest │ ⚠ │ ✗ │ ✗ │
└──────────┴─────────┴─────────┴─────────┘
✓ Full ⚠ Restricted ✗ Denied
<span class="header">USER SHELL LOGIN </span>
admin bash password+key
jacky bash password
monitor false key
<span class="header">GROUP USERS </span>
admin admin
operator jacky
guest monitor
</code></pre>
For details about a group's restrictions, use `show nacm group <name>`:
<pre class="cli"><code>admin@example:/> <b>show nacm group operator</b>
members : jacky
read permission : restricted
write permission : restricted
exec permission : restricted
applicable rules : 4
──────────────────────────────────────────────────────────────────────
<span class="title">permit-system-rpcs</span>
action : permit
operations : exec
target : ietf-system (rpc: *)
──────────────────────────────────────────────────────────────────────
<span class="title">deny-password-access (via '*')</span>
action : deny
operations : *
target : /ietf-system:system/authentication/user/password
──────────────────────────────────────────────────────────────────────
<span class="title">deny-keystore-access (via '*')</span>
action : deny
operations : *
target : ietf-keystore
──────────────────────────────────────────────────────────────────────
<span class="title">deny-truststore-access (via '*')</span>
action : deny
operations : *
target : ietf-truststore
</code></pre>
### Testing Access
The easiest way to test NACM permissions is to log in as the user and try
the operation:
<pre class="cli"><code>$ ssh jacky@host
jacky@example:/> <b>configure</b>
jacky@example:/config/> <b>edit system authentication user admin</b>
jacky@example:/config/system/authentication/user/admin/> <b>set authorized-key foo</b>
Error: Access to the data model "ietf-system" is denied because "jacky" NACM authorization failed.
Error: Failed applying changes (2).
</code></pre>
### NACM Statistics
NACM tracks denied operations. If you suspect permission issues, check
the statistics:
<pre class="cli"><code>admin@example:/> <b>show nacm</b>
...
denied operations : 5
denied data writes : 12
...
</code></pre>
Increasing counters indicate permission denials are occurring.
## Best Practices
1. **Leverage permit-by-default** - The factory configuration uses
`write-default: "permit"` with targeted denials. This is "future proof" -
new features work immediately without NACM updates.
2. **Protect sensitive items globally** - Use `group: ["*"]` rule-list to
deny access to passwords, cryptographic keys, and similar sensitive data.
Admin's permit-all rule (evaluated first) bypasses these denials.
3. **Leverage YANG annotations** - Many sensitive operations are already
protected by `nacm:default-deny-all` in YANG modules (factory-reset,
software upgrades, etc.). Only add explicit permit rules when needed.
4. **Order matters** - Rule-lists are evaluated in order. Place admin's
permit-all rule first so it bypasses global denials.
5. **Use path-based denials** - For protecting specific data (like password
hashes), use path rules. For protecting entire modules (like keystore),
use module-name rules.
6. **Test thoroughly** - Always test user permissions after changes. NACM
errors can be subtle (nodes may be silently omitted from read operations).
7. **Keep it simple** - The factory configuration uses only 6 rules for
three user levels. Fewer rules are easier to understand and maintain.
8. **Document rules** - Use the "comment" field to explain why specific
permissions are granted or denied.
## References
- [RFC 8341: Network Configuration Access Control Model (NACM)][1]
- [RFC 7317: A YANG Data Model for System Management (ietf-system)][3]
- [RFC 8808: A YANG Data Model for Factory Default Settings (ietf-factory-default)][4]
- [RFC 8177: YANG Key Chain (ietf-key-chain)][5]
- [System Configuration - Multiple Users][2]
[1]: https://www.rfc-editor.org/rfc/rfc8341
[2]: system.md#multiple-users
[3]: https://www.rfc-editor.org/rfc/rfc7317
[4]: https://www.rfc-editor.org/rfc/rfc8808
[5]: https://www.rfc-editor.org/rfc/rfc8177
[6]: https://datatracker.ietf.org/doc/html/draft-ietf-netconf-tls-client-server
+1717 -10
View File
File diff suppressed because it is too large Load Diff
-192
View File
@@ -1,192 +0,0 @@
# NTP Server
The NTP (Network Time Protocol) server provides accurate time synchronization
for network clients. It supports both standalone operation with a local
reference clock and hybrid mode where it synchronizes with upstream servers
while serving time to downstream clients.
> [!NOTE]
> The NTP server is mutually exclusive with the NTP client in system
> configuration context.
## Standalone Mode
Configure a standalone NTP server using only a local reference clock:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit ntp</b>
admin@example:/config/ntp/> <b>leave</b>
</code></pre>
When setting up NTP via the CLI the system automatically configures a local
reference clock. The default [stratum](#ntp-stratum-levels) is 16 (unsynchronized),
which is suitable for isolated networks. For production use, configure a specific
stratum level:
<pre class="cli"><code>admin@example:/config/> <b>edit ntp</b>
admin@example:/config/ntp/> <b>set refclock-master master-stratum 10</b>
admin@example:/config/ntp/> <b>leave</b>
</code></pre>
## Server Mode
Synchronize from upstream NTP servers while serving time to clients:
<pre class="cli"><code>admin@example:/config/> <b>edit ntp</b>
admin@example:/config/ntp/> <b>edit unicast-configuration 0.pool.ntp.org type uc-server</b>
admin@example:/config/ntp/…/0.pool.ntp.org/type/uc-server/> <b>set iburst true</b>
admin@example:/config/ntp/…/0.pool.ntp.org/type/uc-server/> <b>end</b>
admin@example:/config/ntp/> <b>edit unicast-configuration 1.pool.ntp.org type uc-server</b>
admin@example:/config/ntp/…/1.pool.ntp.org/type/uc-server/> <b>set iburst true</b>
admin@example:/config/ntp/…/1.pool.ntp.org/type/uc-server/> <b>end</b>
admin@example:/config/ntp/> <b>leave</b>
</code></pre>
The `unicast-configuration` uses a composite key with both address and type.
Both hostnames and IP addresses are supported. The `iburst` option enables
fast initial synchronization.
## Peer Mode
In peer mode, two NTP servers synchronize with each other bidirectionally.
Each server acts as both client and server to the other:
**First peer:**
<pre class="cli"><code>admin@peer1:/config/> <b>edit ntp</b>
admin@peer1:/config/ntp/> <b>edit unicast-configuration 192.168.1.2 type uc-peer</b>
admin@peer1:/config/ntp/…/192.168.1.2/type/uc-peer/> <b>end</b>
admin@peer1:/config/ntp/> <b>set refclock-master master-stratum 8</b>
admin@peer1:/config/ntp/> <b>leave</b>
</code></pre>
**Second peer:**
<pre class="cli"><code>admin@peer2:/config/> <b>edit ntp</b>
admin@peer2:/config/ntp/> <b>edit unicast-configuration 192.168.1.1 type uc-peer</b>
admin@peer2:/config/ntp/…/192.168.1.1/type/uc-peer/> <b>end</b>
admin@peer2:/config/ntp/> <b>set refclock-master master-stratum 8</b>
admin@peer2:/config/ntp/> <b>leave</b>
</code></pre>
This configuration provides mutual synchronization between peers. If one peer
fails, the other continues to serve time to clients.
> [!NOTE]
> The `iburst` and `burst` options are not supported in peer mode.
### Peer Selection in Symmetric Mode
When both peers have the same stratum (as in the example above where both are
stratum 8), NTP's clock selection algorithm uses the **Reference ID** as the
tie-breaker. The Reference ID is typically derived from the peer's IP address
when using a local reference clock.
This means the peer with the **numerically lower IP address** will be selected
as the sync source by the other peer. In the example above:
- peer1 (192.168.1.1) has a lower Reference ID
- peer2 (192.168.1.2) will select peer1 as sync source
This behavior is deterministic and ensures stable clock selection. If you need
a specific peer to be selected, configure it with a lower stratum level than
the other peer.
## Timing Configuration
### Poll Intervals
Control how often the NTP server polls upstream sources:
<pre class="cli"><code>admin@example:/config/ntp/> <b>edit unicast-configuration 0.pool.ntp.org type uc-server</b>
admin@example:/config/ntp/…/0.pool.ntp.org/type/uc-server/> <b>set minpoll 4</b>
admin@example:/config/ntp/…/0.pool.ntp.org/type/uc-server/> <b>set maxpoll 10</b>
admin@example:/config/ntp/…/0.pool.ntp.org/type/uc-server/> <b>end</b>
</code></pre>
Poll intervals are specified as powers of 2:
- `minpoll 4` = poll every 2^4 = 16 seconds (minimum polling rate)
- `maxpoll 10` = poll every 2^10 = 1024 seconds (maximum polling rate)
- Defaults: minpoll 6 (64 seconds), maxpoll 10 (1024 seconds)
Use shorter intervals (minpoll 2-4) for faster convergence in test environments
or peer configurations. Use defaults for production servers.
### Fast Initial Synchronization
The `makestep` directive is automatically configured with safe defaults (1.0
seconds threshold, 3 updates limit) when creating an NTP server. This is
critical for embedded systems without RTC that boot with epoch time.
To customize the values:
<pre class="cli"><code>admin@example:/config/ntp/> <b>edit makestep</b>
admin@example:/config/ntp/makestep/> <b>set threshold 2.0</b>
admin@example:/config/ntp/makestep/> <b>set limit 1</b>
admin@example:/config/ntp/makestep/> <b>end</b>
</code></pre>
- **threshold** - If clock offset exceeds this (in seconds), step immediately
instead of slewing slowly
- **limit** - Number of updates during which stepping is allowed. After this,
only gradual slewing is used for security
With these defaults, a device booting at epoch time (1970-01-01) will sync to
correct time within seconds instead of hours.
## Monitoring
For a quick overview:
To view the sources being used by the NTP client, run:
<pre class="cli"><code>admin@example:/> <b>show ntp</b>
Mode : Client
Stratum : 3
Ref time (UTC) : Sat Jan 24 23:41:42 2026
<span class="header">ADDRESS MODE STATE STRATUM POLL</span>
147.78.228.41 server outlier 2 64s
192.168.0.1 server unusable 0 128s
176.126.86.247 server selected 2 64s
</code></pre>
Check NTP source status:
<pre class="cli"><code>admin@example:/> <b>show ntp source</b>
<span class="header">MS Name/IP address Stratum Poll Reach LastRx Last sample</span>
^+ 147.78.228.41 2 6 007 15 -431us +/- 33.573ms
^* 176.126.86.247 2 6 007 14 -389us +/- 4.307ms
</code></pre>
For detailed information about a specific source:
<pre class="cli"><code>admin@example:/> <b>show ntp source 176.126.86.247</b>
Address : 176.126.86.247
Mode : Server (client mode) [^]
State : Selected sync source [*]
Configured : Yes
Stratum : 2
Poll interval : 7 (2^7 seconds = 128s)
Reachability : 377 (octal) = 11111111b
Last RX : 75s ago
Offset : +2.0us (+0.002000ms)
Delay : 4.270ms (0.004270s)
Dispersion : 205.0us (0.205000ms)
</code></pre>
## NTP Stratum Levels
NTP uses a hierarchical system called **stratum** to indicate distance from
authoritative time sources:
- **Stratum 0**: Reference clocks (atomic clocks)
- **Stratum 1**: Servers directly connected to stratum 0 (e.g., GPS receivers)
- **Stratum 2-15**: Servers that sync from lower stratum (each hop adds one)
- **Stratum 16**: Unsynchronized (invalid)
The default stratum (16) is not suitable for distributing time in isolated
networks, so when setting up an NTP server remember to adjust this value.
Use, e.g., `10`, this is a safe, low-priority value that ensures clients will
prefer upstream-synchronized servers (stratum 1-9) while still having a
fallback time source in isolated networks.
+9 -8
View File
@@ -91,14 +91,15 @@ These `ingress-qos` and `egress-qos` settings are done per VLAN, both
defaulting to '0'. The example below shows how to keep the PCP priority
for packets being routed between two VLAN interfaces.
<pre class="cli"><code>admin@example:/config/> <b>edit interface e1.10</b>
admin@example:/config/interface/e1.10/> <b>set vlan ingress-qos priority from-pcp</b>
admin@example:/config/interface/e1.10/> <b>up</b>
admin@example:/config/> <b>edit interface e1.20</b>
admin@example:/config/interface/e1.20/> <b>set vlan egress-qos pcp from-priority</b>
admin@example:/config/interface/e1.20/> <b>leave</b>
admin@example:/>
</code></pre>
```
admin@example:/config/> edit interface e1.10
admin@example:/config/interface/e1.10/> set vlan ingress-qos priority from-pcp
admin@example:/config/interface/e1.10/> up
admin@example:/config/> edit interface e1.20
admin@example:/config/interface/e1.20/> set vlan egress-qos pcp from-priority
admin@example:/config/interface/e1.20/> leave
admin@example:/>
```
## A complex example
-453
View File
@@ -1,453 +0,0 @@
# Routing
Currently supported YANG models:
| **YANG Model** | **Description** |
|:--------------------------|:--------------------------------|
| ietf-routing | Base model for all other models |
| ietf-ipv4-unicast-routing | Static IPv4 unicast routing |
| ietf-ipv6-unicast-routing | Static IPv6 unicast routing |
| ietf-ospf | OSPF routing |
| ietf-rip | RIP routing |
| infix-routing | Infix deviations and extensions |
The base model, ietf-routing, is where all the other models hook in. It
is used to set configuration and read operational status (RIB tables) in
the other models.
> [!NOTE]
> The standard IETF routing models allows multiple instances, but Infix
> currently *only support one instance* per routing protocol! In the
> examples presented here, the instance name `default` is used.
## IPv4 Static routes
The standard IETF model for static routes reside under the `static`
control plane protocol. For our examples we use the instance name
`default`, you can use any name.
For a route with destination 192.168.200.0/24 via 192.168.1.1:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit routing control-plane-protocol static name default ipv4</b>
admin@example:/config/routing/…/ipv4/> <b>set route 192.168.200.0/24 next-hop next-hop-address 192.168.1.1</b>
admin@example:/config/routing/…/ipv4/> <b>leave</b>
admin@example:/>
</code></pre>
For a "floating" static route with destination 10.0.0.0/16 via a backup
router 192.168.1.1, using the highest possible distance:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit routing control-plane-protocol static name default ipv4</b>
admin@example:/config/routing/…/ipv4/> <b>set route 10.0.0.0/16 next-hop next-hop-address 192.168.1.1 route-preference 254</b>
admin@example:/config/routing/…/ipv4/> <b>leave</b>
admin@example:/>
</code></pre>
> [!TIP]
> Remember to enable [IPv4 forwarding](ip.md#ipv4-forwarding) for the
> interfaces you want to route between.
## IPv6 Static routes
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit routing control-plane-protocol static name default ipv6</b>
admin@example:/config/routing/…/ipv6/> <b>set route 2001:db8:3c4d:200::/64 next-hop next-hop-address 2001:db8:3c4d:1::1</b>
admin@example:/config/routing/…/ipv6/> <b>leave</b>
admin@example:/>
</code></pre>
## OSPFv2 Routing
The system supports OSPF dynamic routing for IPv4, i.e., OSPFv2. To
enable OSPF and set one active interface in area 0:
<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@example:/config/routing/…/ospf/> <b>set area 0.0.0.0 interface e0 enabled</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
> [!TIP]
> Remember to enable [IPv4 forwarding](ip.md#ipv4-forwarding) for all the
> interfaces you want to route between.
### OSPF area types
In addition to *regular* OSPF areas, area types *NSSA* and *Stub* are
also supported. To configure an NSSA area with summary routes:
<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@example:/config/routing/…/ospf/> <b>set area 0.0.0.1 area-type nssa-area</b>
admin@example:/config/routing/…/ospf/> <b>set area 0.0.0.1 summary true</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
### Bidirectional Forwarding Detection (BFD)
It is possible to enable BFD per OSPF interface to speed up detection of
link loss.
<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@example:/config/routing/…/ospf/> <b>set area 0.0.0.0 interface e0 bfd enabled true</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
### OSPF interface settings
We have already seen how to enable OSPF per interface (*enabled true*)
and BFD for OSPF per interface (*bfd enabled true*). These and other
OSPF interface settings are done in context of an OSFP area, e.g., *area
0.0.0.0*. Available commands can be listed using the `?` mark.
<pre class="cli"><code>admin@example:/config/routing/…/> <b>edit ospf area 0.0.0.0</b>
admin@example:/config/routing/…/ospf/area/0.0.0.0/> <b>edit interface e0</b>
admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> <b>set ?</b>
bfd BFD interface configuration.
cost Interface's cost.
dead-interval Interval after which a neighbor is declared down
enabled Enables/disables the OSPF protocol on the interface.
hello-interval Interval between Hello packets (seconds). It must
interface-type Interface type.
passive Enables/disables a passive interface. A passive
retransmit-interval Interval between retransmitting unacknowledged Link
transmit-delay Estimated time needed to transmit Link State Update
admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> set
</code></pre>
For example, setting the OSPF *interface type* to *point-to-point* for
an Ethernet interface can be done as follows.
<pre class="cli"><code>admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/> <b>set interface-type point-to-point</b>
admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/>
</code></pre>
### OSPF global settings
In addition to *area* and *interface* specific settings, OSPF provides
global settings for route redistribution and OSPF router identifier.
<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@example:/config/routing/…/ospf/> <b>set ?</b>
area List of OSPF areas.
default-route-advertise Distribute default route to network
explicit-router-id Defined in RFC 2328. A 32-bit number
redistribute Redistribute protocols into OSPF
admin@example:/config/routing/…/ospf/> set
</code></pre>
- Explicit router ID: By default the router will pick an IP address
from one of its OSPF interfaces as OSPF router ID. An explicit ID is
used to get a deterministic behavior, e.g., `set explicit-router-id
1.1.1.1`.
- Redistribution: `set redistribute static` and `set redistribute connected`
can be used to include static or connected routes into the OSPF routing
domain. These routes are redistributed as *external type-2* (E2)
routes.
- Advertising default route: An OSPF router can be made to distribute
a default route into the OSPF domain by command `set
default-route-advertise enabled`. This route is distributed as long
as the router itself has an *active* default route in its routing
table. By adding command `set default-route-advertise always` the
router will distribute a default route even when it lacks a default
route. The default route will be distributed as an *external type-2*
(E2) route.
### Debug OSPFv2
Using NETCONF and the YANG model *ietf-routing* it is possible to read
the OSPF routing table, neighbors and more, that may be useful for
debugging the OSPFv2 setup. The CLI has various OSPF status commands
such as `show ospf neighbor`, `show ospf interface` and `show ospf
routes`.
<pre class="cli"><code>admin@example:/> <b>show ospf neighbor</b>
<span class="header">Neighbor ID Pri State Up Time Dead Time Address Interface RXmtL RqstL DBsmL</span>
10.1.1.2 1 Full/- 3h46m59s 30.177s 10.1.1.2 e0:10.1.1.1 0 0 0
10.1.1.3 1 Full/- 3h46m55s 34.665s 10.1.1.3 e1:10.1.1.1 0 0 0
admin@example:/>
</code></pre>
For more detailed troubleshooting, OSPF debug logging can be enabled to
capture specific protocol events. Debug messages are written to the
routing log file (`/var/log/routing`).
> [!CAUTION]
> Debug logging significantly increases log output and may impact
> performance. Only enable debug categories needed for troubleshooting,
> and disable them when done.
To enable specific OSPF debug categories:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf debug</b>
admin@example:/config/routing/…/ospf/debug/> <b>set bfd true</b>
admin@example:/config/routing/…/ospf/debug/> <b>set nsm true</b>
admin@example:/config/routing/…/ospf/debug/> <b>leave</b>
admin@example:/>
</code></pre>
Available debug categories include:
- `bfd`: BFD (Bidirectional Forwarding Detection) events
- `packet`: Detailed packet debugging (all OSPF packets)
- `ism`: Interface State Machine events
- `nsm`: Neighbor State Machine events
- `default-information`: Default route origination
- `nssa`: Not-So-Stubby Area events
All debug options are disabled by default. Refer to the `infix-routing`
YANG model for the complete list of available debug options.
To view current debug settings:
<pre class="cli"><code>admin@example:/> <b>show running-config routing control-plane-protocol</b>
</code></pre>
To disable all debug logging, simply delete the debug settings or set
all options back to `false`:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>delete routing control-plane-protocol ospfv2 name default ospf debug</b>
admin@example:/config/> <b>leave</b>
admin@example:/>
</code></pre>
## RIP Routing
The system supports RIP dynamic routing for IPv4, i.e., RIPv2. To enable
RIP and set active interfaces:
<pre class="cli"><code>admin@example:/config/> <b>edit routing control-plane-protocol ripv2 name default rip</b>
admin@example:/config/routing/…/rip/> <b>set interfaces interface e0</b>
admin@example:/config/routing/…/rip/> <b>set interfaces interface e1</b>
admin@example:/config/routing/…/rip/> <b>leave</b>
admin@example:/>
</code></pre>
> [!TIP]
> Remember to enable [IPv4 forwarding](ip.md#ipv4-forwarding) for all the
> interfaces you want to route between.
### RIP interface settings
By default, interfaces send and receive RIPv2 packets. To control the
RIP version per interface:
<pre class="cli"><code>admin@example:/config/routing/…/rip/> <b>edit interfaces interface e0</b>
admin@example:/config/routing/…/rip/interfaces/interface/e0/> <b>set send-version 1</b>
admin@example:/config/routing/…/rip/interfaces/interface/e0/> <b>set receive-version 1-2</b>
admin@example:/config/routing/…/rip/interfaces/interface/e0/> <b>leave</b>
admin@example:/>
</code></pre>
Valid version values are `1`, `2`, or `1-2` (both versions).
To configure a passive interface (advertise network but don't send/receive
RIP updates):
<pre class="cli"><code>admin@example:/config/routing/…/rip/> <b>edit interfaces interface e0</b>
admin@example:/config/routing/…/rip/interfaces/interface/e0/> <b>set passive</b>
admin@example:/config/routing/…/rip/interfaces/interface/e0/> <b>leave</b>
admin@example:/>
</code></pre>
### RIP global settings
RIP supports redistribution of connected and static routes:
<pre class="cli"><code>admin@example:/config/routing/…/rip/> <b>set redistribute connected</b>
admin@example:/config/routing/…/rip/> <b>set redistribute static</b>
admin@example:/config/routing/…/rip/> <b>leave</b>
admin@example:/>
</code></pre>
### Debug RIPv2
The CLI provides various RIP status commands:
<pre class="cli"><code>admin@example:/> <b>show ip rip</b>
Default version control: send version 2, receive version 2
<span class="header"> Interface Send Recv Key-chain </span>
e0 2 2
e1 2 2
Routing for Networks:
e0
e1
Routing Information Sources:
<span class="header"> Gateway BadPackets BadRoutes Distance Last Update</span>
10.0.1.2 0 0 120 00:00:16
Distance: (default is 120)
admin@example:/> <b>show ip rip neighbor</b>
<span class="header">ADDRESS BAD-PACKETS BAD-ROUTES </span>
10.0.1.2 0 0
admin@example:/>
</code></pre>
For more detailed troubleshooting, RIP debug logging can be enabled to
capture specific protocol events. Debug messages are written to the
routing log file (`/var/log/routing`).
> [!CAUTION]
> Debug logging significantly increases log output and may impact
> performance. Only enable debug categories needed for troubleshooting,
> and disable them when done.
To enable specific RIP debug categories:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit routing control-plane-protocol ripv2 name default rip debug</b>
admin@example:/config/routing/…/rip/debug/> <b>set events true</b>
admin@example:/config/routing/…/rip/debug/> <b>set packet true</b>
admin@example:/config/routing/…/rip/debug/> <b>leave</b>
admin@example:/>
</code></pre>
Available debug categories include:
- `events`: RIP events (sending/receiving packets, timers, interface changes)
- `packet`: Detailed packet debugging (packet dumps with origin and port)
- `kernel`: Kernel routing table updates (route add/delete, interface updates)
All debug options are disabled by default. Refer to the `infix-routing`
YANG model for the complete list of available debug options.
To view current debug settings:
<pre class="cli"><code>admin@example:/> <b>show running-config routing control-plane-protocol</b>
</code></pre>
To disable all debug logging, simply delete the debug settings or set
all options back to `false`:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>delete routing control-plane-protocol ripv2 name default rip debug</b>
admin@example:/config/> <b>leave</b>
admin@example:/>
</code></pre>
## View routing table
The routing table can be inspected from the operational datastore, XPath
`/routing/ribs`, using sysrepocfg, NETCONF/RESTCONF, or using the CLI.
### IPv4 routing table
This CLI example shows the IPv4 routing table with a few connected
routes and some routes learned from OSPF. See the next section for
an explanation of route preferences (PREF).
The `>` at the start of a line marks a selected route (in the IETF YANG
model referred to as *active*), if there are more than one route with
the same destination the `*` marks the next-hop used and installed in
the kernel FIB (the YANG model refers to this as *installed*).
<pre class="cli"><code>admin@example:/> <b>show ip route</b>
<span class="header"> DESTINATION PREF NEXT-HOP PROTO UPTIME</span>
>* 0.0.0.0/0 110/2 10.0.23.1 ospfv2 4h2m43s
>* 10.0.0.1/32 110/4000 10.0.13.1 ospfv2 4h2m43s
10.0.0.3/32 110/0 lo ospfv2 4h2m57s
>* 10.0.0.3/32 0/0 lo direct 4h2m58s
10.0.13.0/30 110/2000 e5 ospfv2 4h2m57s
>* 10.0.13.0/30 0/0 e5 direct 4h2m58s
10.0.23.0/30 110/1 e6 ospfv2 4h2m57s
>* 10.0.23.0/30 0/0 e6 direct 4h2m58s
192.168.3.0/24 110/1 e2 ospfv2 4h2m57s
>* 192.168.3.0/24 0/0 e2 direct 4h2m58s
admin@example:/>
</code></pre>
### IPv6 routing table
This CLI example show the IPv6 routing table.
<pre class="cli"><code>admin@example:/> <b>show ipv6 route</b>
<span class="header"> DESTINATION PREF NEXT-HOP PROTO UPTIME</span>
>* ::/0 1/0 2001:db8:3c4d:50::1 static 0h1m20s
>* 2001:db8:3c4d:50::/64 0/0 e6 direct 0h1m20s
>* 2001:db8:3c4d:200::1/128 0/0 lo direct 0h1m20s
* fe80::/64 0/0 e7 direct 0h1m20s
* fe80::/64 0/0 e6 direct 0h1m20s
* fe80::/64 0/0 e5 direct 0h1m20s
* fe80::/64 0/0 e4 direct 0h1m20s
* fe80::/64 0/0 e3 direct 0h1m20s
* fe80::/64 0/0 e2 direct 0h1m20s
>* fe80::/64 0/0 e1 direct 0h1m20s
admin@example:/>
</code></pre>
### Route Preference
The operating system leverages FRRouting ([Frr][0]) as routing engine
for both static and dynamic routing. Even routes injected from a DHCP
client, and IPv4 link-local (IPv4) routes, are injected into Frr to let
it weigh all routes before installing them into the kernel routing table
(sometimes referred to as FIB).
Routes have different weights made up from a *distance* and a *metric*.
The kernel routing table only talks about *metric*, which unfortunately
is **not the same** -- this is one of the reasons why the term *route
preference* is used instead. It is recommended to use the CLI, or any
of the other previously mentioned YANG based front-ends, to inspect the
routing table.
Default distances used (lower numeric value wins):
| **Distance** | **Protocol** |
|--------------|-----------------------------------------|
| 0 | Kernel routes, i.e., connected routes |
| 1 | Static routes |
| 5 | DHCP routes |
| 110 | OSPF |
| 254 | IPv4LL (ZeroConf) device routes |
| 255 | Route will not be used or redistributed |
Hence, a route learned from OSPF may be overridden by a static route set
locally. By default, even a route to the same destination, but with a
different next-hop, learned from a DHCP server wins over an OSPF route.
The distance used for static routes and DHCP routes can be changed by
setting a different *routing preference* value.
> [!NOTE]
> The kernel metric is an unsigned 32-bit value, which is read by Frr as
> (upper) 8 bits distance and 24 bits metric. But it does not write it
> back to the kernel FIB this way, only selected routes are candidates
> to be installed in the FIB by Frr.
### Source protocol
The source protocol describes the origin of the route.
| **Protocol** | **Description** |
|:-------------|:----------------------------------------------------|
| kernel | Added when setting a subnet address on an interface |
| static | User created, learned from DHCP, or IPv4LL |
| ospfv2 | Routes learned from OSPFv2 |
The YANG model *ietf-routing* support multiple ribs but only two are
currently supported, namely `ipv4` and `ipv6`.
[0]: https://frrouting.org/
+2 -2
View File
@@ -350,5 +350,5 @@ the created configuration.
[1]: scripting-sysrepocfg.md#backup-configuration
[2]: scripting-sysrepocfg.md#restore-configuration
[8]: bridging.md
[9]: bridging.md#vlan-filtering-bridge
[8]: networking.md#bridging
[9]: networking.md#vlan-filtering-bridge
+53 -306
View File
@@ -18,116 +18,77 @@ To simplify RESTCONF operations, create a `curl.sh` wrapper script:
#!/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
usage()
{
cat <<EOF >&2
Usage: $0 [-v] [-h HOST] [-d DATASTORE] [-u USER:PASS] METHOD XPATH [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)
-v Verbose mode, use it to display variables and curl command
Methods: GET, POST, PUT, PATCH, DELETE
EOF
exit "$1"
}
check()
{
hint="Note: URL may be missing a module prefix (e.g., ietf-system:system)"
resp="$1"
url="$2"
if ! command -v jq >/dev/null 2>&1; then
printf "%s\n" "$resp"
return
fi
case "$resp" in
*"Syntax error"*)
path_only="${url#*//}"
# Check for common URL error(s), e.g., missing module prefix
case "$path_only" in
*":"*)
printf "%s\n" "$resp" | jq .
;;
*)
printf "%s\n" "$resp" | jq --arg hint "$hint" \
'.["ietf-restconf:errors"].error[] |= . + {comment: $hint}'
;;
esac
;;
*)
printf "%s\n" "$resp" | jq .
;;
esac
}
while getopts "h:d:u:v" opt; do
case $opt in
h) HOST="$OPTARG" ;;
d) DATASTORE="$OPTARG" ;;
u) AUTH="$OPTARG" ;;
v) VERBOSE=1 ;;
*) usage 1 ;;
esac
# 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 XPATH are required" >&2
usage 1
echo "Error: METHOD and PATH are required" >&2
usage 1
fi
METHOD=$1
XPATH=$2
PATH=$2
shift 2
# Ensure XPATH starts with /
case "$XPATH" in
/*) ;;
*) XPATH="/$XPATH" ;;
# 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${XPATH}"
;;
operational)
URL="https://${HOST}/restconf/data${XPATH}"
;;
*)
echo "Error: Invalid datastore '$DATASTORE'. Use: running, operational, or startup" >&2
exit 1
;;
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
if [ "$VERBOSE" ]; then
echo "DS : $DATASTORE"
echo "OP : $METHOD"
echo "XPATH : $XPATH"
echo "AUTH : $AUTH"
echo "=> URL : $URL"
set -x
fi
RESP=$(/usr/bin/curl --silent \
--insecure \
--user "${AUTH}" \
--request "${METHOD}" \
--header "Content-Type: application/yang-data+json" \
--header "Accept: application/yang-data+json" \
"$@" \
"${URL}")
check "$RESP" "$URL"
# 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:
@@ -151,158 +112,6 @@ command-line options or environment variables:
The examples below show both raw `curl` commands and the equivalent using
`curl.sh` where applicable.
## HTTP Methods in RESTCONF
RESTCONF uses standard HTTP methods to perform different operations on
configuration and operational data. Understanding when to use each method is
crucial for correct and safe operations.
### GET - Read Data
Retrieve configuration or operational data without making changes.
**When to use:**
- Reading current configuration
- Querying operational state (interface statistics, routing tables, etc.)
- Discovering what exists before making changes
**Characteristics:**
- Safe operation (no side effects)
- Can be repeated without consequences
- Works on both configuration and operational datastores
**Example:**
```bash
~$ ./curl.sh -h example.local GET /ietf-interfaces:interfaces
```
### PUT - Replace Resource
> [!DANGER] Heads-up!
> PUT replaces everything - missing fields will be deleted!
Replace an entire resource with new content.
**When to use:**
- Replacing entire datastore (backup/restore scenarios)
- Complete reconfiguration of a container
- When you want to ensure the resource matches exactly what you provide
**Characteristics:**
- Replaces all content at the target path
- Any existing data not in the PUT request is **removed**
- Requires complete, valid configuration
- Dangerous if you don't include all necessary fields
**Example:**
```bash
~$ ./curl.sh -h example.local PUT /ietf-system:system \
-d '{"ietf-system:system":{"hostname":"newhost","contact":"admin@example.com"}}'
```
### PATCH - Merge/Update Resource
Partially update a resource by merging changes with existing data.
**When to use:**
- Modifying specific fields while preserving others
- Working with path-based NACM permissions
- Incremental configuration changes
- Safer alternative to PUT for most use cases
**Characteristics:**
- Merges changes with existing configuration
- Only specified fields are modified
- Unspecified fields remain unchanged
- Works with partial data structures
- NACM-friendly (respects path-based permissions)
**Example:**
```bash
~$ ./curl.sh -h example.local PATCH /ietf-interfaces:interfaces \
-d '{"ietf-interfaces:interfaces":{"interface":[{"name":"e0","description":"WAN"}]}}'
```
> [!TIP] Best practice
> Use PATCH instead of PUT for most configuration updates.
### POST - Create New Resource
Create a new resource within a collection or invoke an RPC.
**When to use:**
- Adding new list entries (interfaces, users, routes, etc.)
- Creating resources at specific paths
- Invoking RPC operations (reboot, factory-reset, etc.)
**Characteristics:**
- Creates new resources
- For lists: adds a new element
- For RPCs: executes the operation
- Returns error if resource already exists (for configuration)
**Example - Add IP address:**
```bash
~$ ./curl.sh -h example.local POST \
/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254 \
-d '{"prefix-length": 32}'
```
**Example - Invoke RPC:**
```bash
~$ curl -kX POST -u admin:admin \
-H "Content-Type: application/yang-data+json" \
https://example.local/restconf/operations/ietf-system:system-restart
```
### DELETE - Remove Resource
Delete a resource or configuration element.
**When to use:**
- Removing interfaces, routes, users, etc.
- Deleting specific configuration items
- Cleaning up unwanted configuration
**Characteristics:**
- Removes the resource completely
- Cannot be undone (except by reconfiguration)
- Returns error if resource doesn't exist
**Example:**
```bash
~$ ./curl.sh -h example.local DELETE \
/ietf-interfaces:interfaces/interface=lo/ietf-ip:ipv4/address=192.168.254.254
```
### Quick Reference
| **Method** | **Use Case** | **Safe?** | **Idempotent?** | **NACM Impact** |
|------------|-------------------------|-----------|-----------------|--------------------------|
| GET | Read data | ✓ | ✓ | Read permissions |
| PUT | Replace entire resource | ✗ | ✓ | Full write access needed |
| PATCH | Merge/update fields | ✓ | ✓ | Path-specific write |
| POST | Create new/invoke RPC | ✗ | ✗ | Create/exec permissions |
| DELETE | Remove resource | ✗ | ✓ | Delete permissions |
**Key takeaways:**
- **Use PATCH for updates** - Safer than PUT, works with NACM
- **Use PUT sparingly** - Only when you need complete replacement
- **GET is always safe** - Read as much as you need
- **POST for creation/RPCs** - Creating new items or executing operations
- **DELETE with care** - Cannot be undone
## Discovery & Common Patterns
Before working with specific configuration items, you often need to discover
@@ -436,68 +245,6 @@ Example of updating configuration with inline JSON data:
-d '{"ietf-system:system":{"hostname":"bar"}}'
```
### Update Interface Description
PATCH allows you to modify specific parts of the configuration without
replacing the entire container. This is particularly useful when working
with NACM (Network Access Control Model) permissions that grant access to
specific paths.
**Why use PATCH instead of PUT:**
- **Partial updates**: Only changes specified fields, preserves others
- **NACM-friendly**: Works with path-based access control rules
- **Safer**: Reduces risk of accidentally removing unrelated configuration
**Example - Modify an interface description:**
```bash
~$ curl -kX PATCH -u admin:admin \
-H 'Content-Type: application/yang-data+json' \
-d '{"ietf-interfaces:interfaces":{"interface":[{"name":"e0","description":"WAN Port"}]}}' \
https://example.local/restconf/data/ietf-interfaces:interfaces
```
**Using curl.sh:**
```bash
~$ ./curl.sh -h example.local PATCH /ietf-interfaces:interfaces \
-d '{"ietf-interfaces:interfaces":{"interface":[{"name":"e0","description":"WAN Port"}]}}'
```
**Formatted for readability:**
```bash
~$ curl -kX PATCH -u admin:admin \
-H 'Content-Type: application/yang-data+json' \
-d '{
"ietf-interfaces:interfaces": {
"interface": [
{
"name": "e0",
"description": "WAN Port"
}
]
}
}' \
https://example.local/restconf/data/ietf-interfaces:interfaces
```
**Key points:**
- PATCH URL targets the **container** (`/interfaces`), not a specific interface
- JSON body includes the full structure with the interface array
- Only specified fields are modified; other interface settings remain unchanged
- The `name` field identifies which interface to update
**Verify the change:**
```bash
~$ ./curl.sh -h example.local GET /ietf-interfaces:interfaces/interface=e0 2>/dev/null \
| jq '.["ietf-interfaces:interface"][0].description'
"WAN Port"
```
### Add IP Address to Interface
Add an IP address to the loopback interface:
+3 -6
View File
@@ -1,9 +1,6 @@
> [!WARNING] Deprecated - Use RESTCONF Instead
>
> This legacy interface requires elevated privileges (`sudo sysrepocfg`) even
> for admin users and is no longer intended for production use. All scripting
> should use [RESTCONF][1] as the standard management interface. There is
> however an NACM compliant replacement `copy` that can be used without sudo.
> [!NOTE]
> This method is a legacy "simple and human-friendly" way to manage the
> system. These days we strongly recommend using [RESTCONF][1] instead.
# Legacy Scripting
+6 -13
View File
@@ -5,20 +5,14 @@ provides a convenient way to collect comprehensive system diagnostics.
This command gathers configuration files, logs, network state, and other
system information into a single compressed archive.
> [!NOTE]
> The `support collect` command should be run with `sudo` to collect
> complete system information (kernel logs, hardware details, etc.).
> Use the `--unprivileged` option to run as a regular user in degraded
> data collection mode.
## Collecting Support Data
To collect support data and save it to a file:
```bash
admin@host:~$ sudo support collect > support-data.tar.gz
admin@host:~$ support collect > support-data.tar.gz
(admin@host) Password: ***********
Starting support data collection from host...
Collecting to: /var/lib/support
This may take up to a minute. Please wait...
Tailing /var/log/messages for 30 seconds (please wait)...
Log tail complete.
@@ -30,7 +24,7 @@ admin@host:~$ ls -l support-data.tar.gz
The command can also be run remotely via SSH from your workstation:
```bash
$ ssh admin@host 'sudo support collect' > support-data.tar.gz
$ ssh admin@host support collect > support-data.tar.gz
...
```
@@ -44,9 +38,8 @@ For secure transmission of support data, the archive can be encrypted
with GPG using a password:
```bash
admin@host:~$ sudo support collect -p mypassword > support-data.tar.gz.gpg
admin@host:~$ support collect -p mypassword > support-data.tar.gz.gpg
Starting support data collection from host...
Collecting to: /var/lib/support
This may take up to a minute. Please wait...
...
Collection complete. Creating archive...
@@ -59,8 +52,8 @@ but the local ssh client may then echo the password.
> [!TIP]
> To hide the encryption password for an SSH session, the script supports
> reading from stdin:
> `echo "$MYSECRET" | ssh user@device 'sudo support collect -p' >
> reading from stdin:
> `echo "$MYSECRET" | ssh user@device support collect -p >
> file.tar.gz.gpg`
After transferring the resulting file to your workstation, decrypt it
+93 -78
View File
@@ -21,19 +21,20 @@ an example.
For a list of available log facilities, see the table in a later section.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit syslog actions log-file file:/media/log/mylog</b>
admin@example:/config/syslog/…/file:/media/log/mylog/> <b>set facility-list</b>
```
admin@example:/> configure
admin@example:/config/> edit syslog actions log-file file:/media/log/mylog
admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list
all audit auth authpriv console cron cron2 daemon ftp kern
local0 local1 local2 local3 local4 local5 local6 local7 lpr mail
news ntp syslog user uucp
admin@example:/config/syslog/…/file:/media/log/mylog/> <b>set facility-list all severity</b>
admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list all severity
alert all critical debug emergency error info none notice warning
admin@example:/config/syslog/…/file:/media/log/mylog/> <b>set facility-list all severity critical</b>
admin@example:/config/syslog/…/file:/media/log/mylog/> <b>set facility-list mail severity warning</b>
admin@example:/config/syslog/…/file:/media/log/mylog/> <b>leave</b>
admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list all severity critical
admin@example:/config/syslog/…/file:/media/log/mylog/> set facility-list mail severity warning
admin@example:/config/syslog/…/file:/media/log/mylog/> leave
admin@example:/>
</code></pre>
```
> [!IMPORTANT]
> The `log-file` syntax requires the leading prefix `file:`. If the
@@ -49,10 +50,11 @@ disk with outdated logs. A rotated file is saved in stages and older
ones are also compressed (using `gzip`). Use the `show log` command in
admin-exec context to start the log file viewer:
<pre class="cli"><code>admin@example:/config/syslog/> <b>do show log</b>
```
admin@example:/config/syslog/> do show log
log log.0 log.1.gz log.2.gz log.3.gz log.4.gz log.5.gz
admin@example:/config/syslog/> <b>do show log log.1.gz</b>
</code></pre>
admin@example:/config/syslog/> do show log log.1.gz
```
> [!TIP]
> Use the Tab key on your keyboard list available log files. The `do`
@@ -66,48 +68,51 @@ Log file rotation can be configured both globally and per log file.
Here we show the global settings, the set up is the same for per log
file, which if unset inherit the global settings:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit syslog file-rotation</b>
admin@example:/config/syslog/file-rotation/> <b>show</b>
```
admin@example:/> configure
admin@example:/config/> edit syslog file-rotation
admin@example:/config/syslog/file-rotation/> show
admin@example:/config/syslog/file-rotation/>
</code></pre>
```
The defaults are not shown. We can inspect them by asking the YANG
model for the help texts:
<pre class="cli"><code>admin@example:/config/syslog/file-rotation/> <b>help</b>
```
admin@example:/config/syslog/file-rotation/> help
max-file-size number-of-files
admin@example:/config/syslog/file-rotation/> <b>help max-file-size</b>
<b>NAME</b>
admin@example:/config/syslog/file-rotation/> help max-file-size
NAME
max-file-size kilobytes
<b>DESCRIPTION</b>
DESCRIPTION
Maximum log file size (kiB), before rotation.
<b>DEFAULT</b>
DEFAULT
1024
admin@example:/config/syslog/file-rotation/> <b>help number-of-files</b>
<b>NAME</b>
admin@example:/config/syslog/file-rotation/> help number-of-files
NAME
number-of-files [0..4294967295]
<b>DESCRIPTION</b>
DESCRIPTION
Maximum number of log files retained.
<b>DEFAULT</b>
DEFAULT
10
</code></pre>
```
To change the defaults to something smaller, 512 kiB and 20 (remember
everything after .0 is compressed, and text compresses well):
<pre class="cli"><code>admin@example:/config/syslog/file-rotation/> <b>set max-file-size 512</b>
admin@example:/config/syslog/file-rotation/> <b>set number-of-files 20</b>
admin@example:/config/syslog/file-rotation/> <b>show</b>
```
admin@example:/config/syslog/file-rotation/> set max-file-size 512
admin@example:/config/syslog/file-rotation/> set number-of-files 20
admin@example:/config/syslog/file-rotation/> show
number-of-files 20;
max-file-size 512;
admin@example:/config/syslog/file-rotation/> <b>leave</b>
admin@example:/config/syslog/file-rotation/> leave
admin@example:/>
</code></pre>
```
## Log Format
@@ -130,13 +135,14 @@ perform time stamping at the time of arrival.
Configuring the log format is the same for log files and remotes:
<pre class="cli"><code>admin@example:/config/> <b>edit syslog actions log-file file:foobar</b>
admin@example:/config/syslog/…/file:foobar/> <b>set log-format</b>
```
admin@example:/config/> edit syslog actions log-file file:foobar
admin@example:/config/syslog/…/file:foobar/> set log-format
bsd rfc3164 rfc5424
admin@example:/config/syslog/…/file:foobar/> <b>set log-format rfc5424</b>
admin@example:/config/syslog/…/file:foobar/> <b>leave</b>
admin@example:/config/syslog/…/file:foobar/> set log-format rfc5424
admin@example:/config/syslog/…/file:foobar/> leave
admin@example:/>
</code></pre>
```
## Log to Remote Server
@@ -152,18 +158,19 @@ remote syslog servers do not support receiving time stamped log messages
-- this is of course entirely dependent on how the remote server is set
up, as well as local policy.
<pre class="cli"><code>admin@example:/config/> <b>edit syslog</b>
```
admin@example:/config/> edit syslog
actions file-rotation server
admin@example:/config/> <b>edit syslog actions destination moon</b>
admin@example:/config/syslog/…/moon/> <b>set</b>
admin@example:/config/> edit syslog actions destination moon
admin@example:/config/syslog/…/moon/> set
facility-list log-format udp
admin@example:/config/syslog/…/moon/> <b>set udp</b>
admin@example:/config/syslog/…/moon/> set udp
address port
admin@example:/config/syslog/…/moon/> <b>set udp address 192.168.0.12</b>
admin@example:/config/syslog/…/moon/> <b>set facility-list container severity all</b>
admin@example:/config/syslog/…/moon/> <b>leave</b>
admin@example:/config/syslog/…/moon/> set udp address 192.168.0.12
admin@example:/config/syslog/…/moon/> set facility-list container severity all
admin@example:/config/syslog/…/moon/> leave
admin@example:/>
</code></pre>
```
> [!TIP]
> The alternatives shown below each prompt in the example above can be
@@ -174,13 +181,14 @@ admin@example:/>
The syslog server can act as a log sink for other devices on a LAN. For
this to work you need a static IP address, here we use 10.0.0.1/24.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit syslog server</b>
admin@example:/config/syslog/server/> <b>set enabled true</b>
admin@example:/config/syslog/server/> <b>set listen udp 514 address 10.0.0.1</b>
admin@example:/config/syslog/server/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> edit syslog server
admin@example:/config/syslog/server/> set enabled true
admin@example:/config/syslog/server/> set listen udp 514 address 10.0.0.1
admin@example:/config/syslog/server/> leave
admin@example:/>
</code></pre>
```
See the above [Log to File](#log-to-file) section on how to set up
filtering of received logs to local files. Advanced filtering based
@@ -200,12 +208,13 @@ Messages can be filtered using regular expressions (POSIX extended regex)
on the message content. This is useful when you want to log only messages
containing specific keywords or patterns:
<pre class="cli"><code>admin@example:/config/> <b>edit syslog actions log-file file:errors</b>
admin@example:/config/syslog/…/file:errors/> <b>set pattern-match "ERROR|CRITICAL|FATAL"</b>
admin@example:/config/syslog/…/file:errors/> <b>set facility-list all severity info</b>
admin@example:/config/syslog/…/file:errors/> <b>leave</b>
```
admin@example:/config/> edit syslog actions log-file file:errors
admin@example:/config/syslog/…/file:errors/> set pattern-match "ERROR|CRITICAL|FATAL"
admin@example:/config/syslog/…/file:errors/> set facility-list all severity info
admin@example:/config/syslog/…/file:errors/> leave
admin@example:/>
</code></pre>
```
This will log all messages containing ERROR, CRITICAL, or FATAL.
@@ -215,20 +224,22 @@ By default, severity filtering uses "equals-or-higher" comparison,
meaning a severity of `error` will match error, critical, alert, and
emergency messages. You can change this behavior:
<pre class="cli"><code>admin@example:/config/> <b>edit syslog actions log-file file:daemon-errors</b>
admin@example:/config/syslog/…/file:daemon-errors/> <b>set facility-list daemon</b>
admin@example:/config/syslog/…/daemon/> <b>set severity error</b>
admin@example:/config/syslog/…/daemon/> <b>set advanced-compare compare equals</b>
admin@example:/config/syslog/…/daemon/> <b>leave</b>
```
admin@example:/config/> edit syslog actions log-file file:daemon-errors
admin@example:/config/syslog/…/file:daemon-errors/> set facility-list daemon
admin@example:/config/syslog/…/daemon/> set severity error
admin@example:/config/syslog/…/daemon/> set advanced-compare compare equals
admin@example:/config/syslog/…/daemon/> leave
admin@example:/>
</code></pre>
```
This will log only `error` severity messages, not higher severities.
You can also block specific severities:
<pre class="cli"><code>admin@example:/config/syslog/…/daemon/> <b>set advanced-compare action block</b>
</code></pre>
```
admin@example:/config/syslog/…/daemon/> set advanced-compare action block
```
This will exclude `error` messages from the log.
@@ -237,12 +248,13 @@ This will exclude `error` messages from the log.
When acting as a log server, you can filter messages by hostname. This
is useful for directing logs from different devices to separate files:
<pre class="cli"><code>admin@example:/config/> <b>edit syslog actions log-file file:router1</b>
admin@example:/config/syslog/…/file:router1/> <b>set hostname-filter router1</b>
admin@example:/config/syslog/…/file:router1/> <b>set facility-list all severity info</b>
admin@example:/config/syslog/…/file:router1/> <b>leave</b>
```
admin@example:/config/> edit syslog actions log-file file:router1
admin@example:/config/syslog/…/file:router1/> set hostname-filter router1
admin@example:/config/syslog/…/file:router1/> set facility-list all severity info
admin@example:/config/syslog/…/file:router1/> leave
admin@example:/>
</code></pre>
```
Multiple hostnames can be added to the filter list.
@@ -251,14 +263,15 @@ Multiple hostnames can be added to the filter list.
For more advanced filtering, you can match on specific message properties
using various comparison operators:
<pre class="cli"><code>admin@example:/config/> <b>edit syslog actions log-file file:myapp</b>
admin@example:/config/syslog/…/file:myapp/> <b>edit property-filter</b>
admin@example:/config/syslog/…/property-filter/> <b>set property programname</b>
admin@example:/config/syslog/…/property-filter/> <b>set operator isequal</b>
admin@example:/config/syslog/…/property-filter/> <b>set value myapp</b>
admin@example:/config/syslog/…/property-filter/> <b>leave</b>
```
admin@example:/config/> edit syslog actions log-file file:myapp
admin@example:/config/syslog/…/file:myapp/> edit property-filter
admin@example:/config/syslog/…/property-filter/> set property programname
admin@example:/config/syslog/…/property-filter/> set operator isequal
admin@example:/config/syslog/…/property-filter/> set value myapp
admin@example:/config/syslog/…/property-filter/> leave
admin@example:/>
</code></pre>
```
Available properties:
- `msg`: Message body
@@ -277,13 +290,15 @@ Available operators:
The comparison can be made case-insensitive:
<pre class="cli"><code>admin@example:/config/syslog/…/property-filter/> <b>set case-insensitive true</b>
</code></pre>
```
admin@example:/config/syslog/…/property-filter/> set case-insensitive true
```
Or negated to exclude matching messages:
<pre class="cli"><code>admin@example:/config/syslog/…/property-filter/> <b>set negate true</b>
</code></pre>
```
admin@example:/config/syslog/…/property-filter/> set negate true
```
### Facilities
+32
View File
@@ -0,0 +1,32 @@
# System Tuning Guide
## Memory
Default memory tuning is defined in `/etc/sysctl.d/vm.conf`, optimized for embedded network devices with 512MB-4GB RAM.
### For Systems with 4GB+ Memory
Systems with more memory can afford to be less aggressive with cache reclaim.
```conf
# Allow more dirty pages before writeback
vm.dirty_ratio=15
vm.dirty_background_ratio=10
# Less aggressive watermark (memory pressure less critical)
vm.watermark_scale_factor=100
```
### For Systems with Heavy Filesystem Activity
Unusual for network equipment, but may occur on systems with extensive logging or storage features.
```conf
# Allow more dirty pages for better write batching
vm.dirty_ratio=20
vm.dirty_background_ratio=10
# Longer dirty page expiration for write coalescing
vm.dirty_expire_centisecs=3000
```
+124 -337
View File
@@ -6,7 +6,7 @@ like Message of the Day (login message) and user login shell. More
on this later on in this document.
For the sake of brevity, the hostname in the following examples has been
shortened to `example`. The default hostname is composed from a product
shortened to `host`. The default hostname is composed from a product
specific string followed by the last three octets of the system base MAC
address, e.g., `switch-12-34-56`. An example of how to change the
hostname is included below.
@@ -22,12 +22,13 @@ hostname is included below.
User management, including passwords, SSH keys, remote authentication is
available in the system authentication configuration context.
<pre class="cli"><code>admin@example:/config/> <b>edit system authentication user admin</b>
admin@example:/config/system/…/user/admin/> <b>change password</b>
```
admin@host:/config/> edit system authentication user admin
admin@host:/config/system/authentication/user/admin/> change password
New password:
Retype password:
admin@example:/config/system//user/admin/> <b>leave</b>
</code></pre>
admin@host:/config/system/authentication/user/admin/> leave
```
The `change password` command starts an interactive dialogue that asks
for the new password, with a confirmation, and then salts and encrypts
@@ -55,331 +56,116 @@ are supported.
With SSH keys in place it is possible to disable password login, just
remember to verify SSH login and network connectivity before doing so.
<pre class="cli"><code>admin@example:/config/> <b>edit system authentication user admin</b>
admin@example:/config/system/…/user/admin/> <b>edit authorized-key admin@example</b>
admin@example:/config/system/…/example@host/> <b>set algorithm ssh-rsa</b>
admin@example:/config/system/…/example@host/> <b>set key-data AAAAB3NzaC1yc2EAAAADAQABAAABgQC8iBL42yeMBioFay7lty1C4ZDTHcHyo739gc91rTTH8SKvAE4g8Rr97KOz/8PFtOObBrE9G21K7d6UBuPqmd0RUF2CkXXN/eN2PBSHJ50YprRFt/z/304bsBYkDdflKlPDjuSmZ/+OMp4pTsq0R0eNFlX9wcwxEzooIb7VPEdvWE7AYoBRUdf41u3KBHuvjGd1M6QYJtbFLQMMTiVe5IUfyVSZ1RCxEyAB9fR9CBhtVheTVsY3iG0fZc9eCEo89ErDgtGUTJK4Hxt5yCNwI88YaVmkE85cNtw8YwubWQL3/tGZHfbbQ0fynfB4kWNloyRHFr7E1kDxuX5+pbv26EqRdcOVGucNn7hnGU6C1+ejLWdBD7vgsoilFrEaBWF41elJEPKDzpszEijQ9gTrrWeYOQ+x++lvmOdssDu4KvGmj2K/MQTL2jJYrMJ7GDzsUu3XikChRL7zNfS2jYYQLzovboUCgqfPUsVba9hqeX3U67GsJo+hy5MG9RSry4+ucHs=</b>
admin@example:/config/system//example@host/> <b>show</b>
```
admin@host:/config/> edit system authentication user admin
admin@host:/config/system/authentication/user/admin/> edit authorized-key example@host
admin@host:/config/system/authentication/user/admin/authorized-key/example@host/> set algorithm ssh-rsa
admin@host:/config/system/authentication/user/admin/authorized-key/example@host/> set key-data AAAAB3NzaC1yc2EAAAADAQABAAABgQC8iBL42yeMBioFay7lty1C4ZDTHcHyo739gc91rTTH8SKvAE4g8Rr97KOz/8PFtOObBrE9G21K7d6UBuPqmd0RUF2CkXXN/eN2PBSHJ50YprRFt/z/304bsBYkDdflKlPDjuSmZ/+OMp4pTsq0R0eNFlX9wcwxEzooIb7VPEdvWE7AYoBRUdf41u3KBHuvjGd1M6QYJtbFLQMMTiVe5IUfyVSZ1RCxEyAB9fR9CBhtVheTVsY3iG0fZc9eCEo89ErDgtGUTJK4Hxt5yCNwI88YaVmkE85cNtw8YwubWQL3/tGZHfbbQ0fynfB4kWNloyRHFr7E1kDxuX5+pbv26EqRdcOVGucNn7hnGU6C1+ejLWdBD7vgsoilFrEaBWF41elJEPKDzpszEijQ9gTrrWeYOQ+x++lvmOdssDu4KvGmj2K/MQTL2jJYrMJ7GDzsUu3XikChRL7zNfS2jYYQLzovboUCgqfPUsVba9hqeX3U67GsJo+hy5MG9RSry4+ucHs=
admin@host:/config/system/authentication/user/admin/authorized-key/example@host/> show
algorithm ssh-rsa;
key-data AAAAB3NzaC1yc2EAAAADAQABAAABgQC8iBL42yeMBioFay7lty1C4ZDTHcHyo739gc91rTTH8SKvAE4g8Rr97KOz/8PFtOObBrE9G21K7d6UBuPqmd0RUF2CkXXN/eN2PBSHJ50YprRFt/z/304bsBYkDdflKlPDjuSmZ/+OMp4pTsq0R0eNFlX9wcwxEzooIb7VPEdvWE7AYoBRUdf41u3KBHuvjGd1M6QYJtbFLQMMTiVe5IUfyVSZ1RCxEyAB9fR9CBhtVheTVsY3iG0fZc9eCEo89ErDgtGUTJK4Hxt5yCNwI88YaVmkE85cNtw8YwubWQL3/tGZHfbbQ0fynfB4kWNloyRHFr7E1kDxuX5+pbv26EqRdcOVGucNn7hnGU6C1+ejLWdBD7vgsoilFrEaBWF41elJEPKDzpszEijQ9gTrrWeYOQ+x++lvmOdssDu4KvGmj2K/MQTL2jJYrMJ7GDzsUu3XikChRL7zNfS2jYYQLzovboUCgqfPUsVba9hqeX3U67GsJo+hy5MG9RSry4+ucHs=;
admin@example:/config/system//example@host/> <b>leave</b>
</code></pre>
admin@host:/config/system/authentication/user/admin/authorized-key/example@host/> leave
```
> [!NOTE]
> The `ssh-keygen` program already base64 encodes the public key data,
> so there is no need to use the `text-editor` command, `set` does the
> job.
## Multiple Users
The factory configuration provides three hierarchical user group levels by
default: **guest ⊂ operator ⊂ admin**. These levels work out-of-the-box
with sensible permissions - operators can configure the system immediately,
while sensitive items (passwords, cryptographic keys) remain protected.
The system supports multiple users and multiple user levels, or groups,
that a user can be a member of. Access control is entirely handled by
the NETCONF ["NACM"][3] YANG model, which provides granular access to
configuration, data, and RPC commands over NETCONF.
The default levels provide different access to system resources and
configuration:
- **Admin**: Full system access - can manage users, upgrade software,
restart the system, and modify all configuration including network
settings, routing, and firewall rules.
- **Operator**: Configuration access - can modify most system settings
including network interfaces, routing, firewall, hostname, and more.
*Cannot access* password hashes, cryptographic keys, or perform
sensitive operations (factory reset, software upgrade).
- **Guest**: Read-only access - can view operational state and
configuration but cannot modify anything or execute operations.
System access control is handled by the [ietf-netconf-acm][3] YANG model,
usually referred to as [NACM](nacm.md), which provides granular access to
configuration, data, and RPC commands. The hierarchical levels in the system
are determined by:
1. **NACM permissions** - what the user can access
2. **Shell setting** - which command-line interface the user can use
By default the system ships with a single user, `admin`, in the `admin`
group. There are no restrictions on the number of users with admin
privileges, nor is the `admin` user reserved or protected -- it can be
removed from the configuration. However, it is strongly recommended to
keep at least one user with administrator privileges, otherwise the only
way to regain full access is to perform a *factory reset*.
For an overview of users and groups on the system, there is an admin-exec
command:
<pre class="cli"><code>admin@example:/> <b>show nacm</b>
enabled : yes
default read access : permit
default write access : permit
default exec access : permit
denied operations : 0
denied data writes : 0
denied notifications : 0
┌──────────┬─────────┬─────────┬─────────┐
│ GROUP │ READ │ WRITE │ EXEC │
├──────────┼─────────┼─────────┼─────────┤
│ admin │ ✓ │ ✓ │ ✓ │
│ operator │ ⚠ │ ⚠ │ ⚠ │
│ guest │ ⚠ │ ✗ │ ✗ │
└──────────┴─────────┴─────────┴─────────┘
✓ Full ⚠ Restricted ✗ Denied
<span class="header">USER SHELL LOGIN </span>
admin bash password+key
jacky clish password
monitor false key
<span class="header">GROUP USERS </span>
admin admin
operator jacky
guest monitor
</code></pre>
The permissions matrix shows effective access for each NACM group:
- **✓ Full** (green) - unrestricted access
- **⚠ Restricted** (yellow) - access with exceptions, use `show nacm group`
for details
- **✗ Denied** (red) - no access
For detailed information about a specific group's rules:
<pre class="cli"><code>admin@example:/> <b>show nacm group operator</b>
members : jacky
read permission : restricted
write permission : restricted
exec permission : restricted
applicable rules : 4
──────────────────────────────────────────────────────────────────────
<span class="title">permit-system-rpcs</span>
action : permit
operations : exec
target : ietf-system (rpc: *)
comment : Operators can reboot, shutdown, and set system time.
──────────────────────────────────────────────────────────────────────
<span class="title">deny-password-access (via '*')</span>
action : deny
operations : *
target : /ietf-system:system/authentication/user/password
comment : No user except admins can access password hashes.
──────────────────────────────────────────────────────────────────────
<span class="title">deny-keystore-access (via '*')</span>
action : deny
operations : *
target : ietf-keystore
comment : No user except admins can access cryptographic keys.
──────────────────────────────────────────────────────────────────────
<span class="title">deny-truststore-access (via '*')</span>
action : deny
operations : *
target : ietf-truststore
comment : No user except admins can access trust store.
</code></pre>
For user details:
<pre class="cli"><code>admin@example:/> <b>show nacm user jacky</b>
shell : clish
login : password
nacm group : operator
read permission : restricted
write permission : restricted
exec permission : restricted
For detailed rules, use: show nacm group &lt;name&gt;
</code></pre>
By default the system ships with a single group, `admin`, which the
default user `admin` is a member of. The broad permissions granted by
the `admin` group is what gives its users full system administrator
privileges. There are no restrictions on the number of users with
administrator privileges, nor is the `admin` user reserved or protected
in any way -- it is completely possible to remove the default `admin`
user from the configuration. However, it is recommended to keep at
least one user with administrator privileges in the system, otherwise
the only way to regain full access is to perform a *factory reset*.
### Adding a User
Creating a new user starts with defining the user account in the system:
Similar to how to change password, adding a new user is done using the
same set of commands:
<pre class="cli"><code>admin@example:/config/> <b>edit system authentication user jacky</b>
admin@example:/config/system/…/user/jacky/> <b>change password</b>
```
admin@host:/config/> edit system authentication user jacky
admin@host:/config/system/authentication/user/jacky/> change password
New password:
Retype password:
admin@example:/config/system//user/jacky/> <b>leave</b>
</code></pre>
admin@host:/config/system/authentication/user/jacky/> leave
```
> [!TIP]
> It is also possible to use <kbd>set password ...</kbd> if you have the
> fully crypted and salted string ready. This can be created offline
> with the [`mkpasswd(1)`][5] tool, or the built-in CLI version <kbd>do
> password encrypt [OPTS]</kbd>. The `do` prefix is handy for reaching
> all top-level commands when in configure context.
An authorized SSH key is added the same way as presented previously.
An authorized SSH key can be added the same way as described in the
previous sections.
### Adding a User to the Admin Group
By default, shell access is disabled (`shell false`). To allow CLI/SSH
access, set the shell:
The following commands add user `jacky` to the `admin` group.
<pre class="cli"><code>admin@example:/config/> <b>edit system authentication user jacky</b>
admin@example:/config/system/…/user/jacky/> <b>set shell clish</b>
admin@example:/config/system/…/user/jacky/> <b>leave</b>
</code></pre>
Available shells:
- `bash` - Full Bourne-again shell (recommended for admins only)
- `sh` - POSIX shell (recommended for admins only)
- `clish` - Limited CLI-only shell (recommended for operators and guests)
- `false` - No shell access (default)
> [!WARNING] Security Notice
> For security reasons, it is strongly recommended to limit non-admin users
> to the `clish` shell, which provides CLI access without exposing the
> underlying UNIX system. Reserve `bash` and `sh` for administrators who
> need full system access for debugging and maintenance.
>
> Note that shell and CLI access is not always necessary - the system
> supports NETCONF and RESTCONF for remote management and automation.
> Setting `shell false` for users who only need programmatic access
> minimizes the attack surface and improves overall system security.
### Adding a User to a Group
To assign a user to a specific privilege level, add them to the
corresponding NACM group:
**Operator user:**
<pre class="cli"><code>admin@example:/config/> <b>edit nacm group operator</b>
admin@example:/config/nacm/group/operator/> <b>set user-name jacky</b>
admin@example:/config/nacm/group/operator/> <b>leave</b>
</code></pre>
**Adding another admin:**
<pre class="cli"><code>admin@example:/config/> <b>edit nacm group admin</b>
admin@example:/config/nacm/group/admin/> <b>set user-name alice</b>
admin@example:/config/nacm/group/admin/> <b>leave</b>
</code></pre>
**Guest user:**
<pre class="cli"><code>admin@example:/config/> <b>edit nacm group guest</b>
admin@example:/config/nacm/group/guest/> <b>set user-name monitor</b>
admin@example:/config/nacm/group/guest/> <b>leave</b>
</code></pre>
> [!TIP]
> For technical details about NACM rule evaluation, module-name vs path
> matching, and creating custom access control policies, see the
> [NACM Technical Guide](nacm.md).
### Access Control Matrix
The following table shows what each user level can do based on the NACM rules
and shell access configured for each user:
- **Admin**: `bash` — full system access
- **Operator**: `clish` — CLI-only access without UNIX system exposure
- **Guest**: `false` — no shell access
| Feature | Admin | Operator | Guest |
|------------------------|-------|----------|-----------|
| Network interfaces | ✓ | ✓ | Read only |
| Routing (FRR) | ✓ | ✓ | Read only |
| Firewall rules | ✓ | ✓ | Read only |
| VLANs/bridges | ✓ | ✓ | Read only |
| Containers | ✓ | ✓ | Read only |
| Hostname/system config | ✓ | ✓ | Read only |
| CLI/SSH access | ✓ | ✓ | ✗ |
| System restart | ✓ | ✓ | ✗ |
| Set date/time | ✓ | ✓ | ✗ |
| System reboot | ✓ | ✓ | ✗ |
| System shutdown | ✓ | ✓ | ✗ |
| User management | ✓ | ✗ | Read only |
| Keystore (certs/keys) | ✓ | ✗ | ✗ |
| Truststore | ✓ | ✗ | ✗ |
| Read passwords/secrets | ✓ | ✗ | ✗ |
| NACM rules | ✓ | ✗ | ✗ |
| Factory reset | ✓ | ✗ | ✗ |
| Software upgrade | ✓ | ✗ | ✗ |
```
admin@host:/config/> edit nacm group admin
admin@host:/config/nacm/group/admin/> set user-name jacky
admin@host:/config/nacm/group/admin/> leave
```
### Security Aspects
The three default user levels are implemented through a combination of NACM
rules and UNIX group membership. Access control is permission-based, not
name-based - the system detects user levels by examining their NACM
permissions and shell settings.
**Admin users** have unrestricted NACM access with the following rule:
The NACM user levels apply primarily to NETCONF, with exception of the
`admin` group which is granted full system administrator privileges to
the underlying UNIX system with the following ACL rules:
```json
...
"module-name": "*",
"access-operations": "*",
"action": "permit"
"action": "permit",
...
```
Admin users are automatically added to the UNIX `wheel` and `frrvty`
groups, granting them `sudo` privileges and access to FRR routing
protocols. This makes it possible to use all the underlying UNIX
tooling, which can be very useful for debugging, but please use with
care -- the system is designed to be managed through the CLI and
NETCONF, not directly via shell commands.
A user in the `admin` group is allowed to also use a POSIX login shell
and use the `sudo` command to perform system administrative commands.
This makes it possible to use all the underlying UNIX tooling, which
to many can be very useful, in particular when debugging a system, but
please remember to use with care -- the system is not built to require
managing from the shell. The tools available in the CLI and automated
services, started from the system's configuration, are the recommended
way of using the system, in addition to NETCONF tooling.
**Operator users** use the permit-by-default NACM model (`write-default:
"permit"`), which means they can configure most system settings without
explicit permit rules. This design is "future proof" - when new features
are added, operators can immediately use them.
The following are explicitly denied to operators through global NACM rules:
- Password hashes (`/ietf-system:system/authentication/user/password`)
- Cryptographic keys (`ietf-keystore` module)
- Trust store certificates (`ietf-truststore` module)
Additionally, sensitive operations like factory reset, software upgrades,
and system shutdown are protected by YANG-level `nacm:default-deny-all`
annotations and remain restricted to administrators.
Operators are automatically added to the UNIX `operator` and `frrvty`
groups, granting them `sudo` privileges for network operations and FRR
access.
**Guest users** have read-only NACM access through an explicit deny rule
that blocks all write and exec operations (`create update delete exec`),
while `read-default: "permit"` allows viewing configuration and state.
Guests receive no special UNIX group memberships. The shell setting
determines whether guests can access the CLI (`clish`) or are restricted
from shell access entirely (`false`).
All users, regardless of level, are denied access to password hashes and
cryptographic key material through global NACM rules.
## Changing Hostname
Notice how the hostname in the prompt does not change until the change
is committed by issuing the `leave` command.
<pre class="cli"><code>admin@example:/config/> <b>edit system</b>
admin@example:/config/system/> <b>set hostname myrouter</b>
admin@example:/config/system/> <b>leave</b>
admin@myrouter:/>
</code></pre>
```
admin@host:/config/> edit system
admin@host:/config/system/> set hostname example
admin@host:/config/system/> leave
admin@example:/>
```
The hostname is advertised over mDNS-SD in the `.local` domain. If
another device already has claimed the `myrouter.local` CNAME, in our
another device already has claimed the `example.local` CNAME, in our
case, mDNS will advertise a "uniqified" variant, usually suffixing with
an index, e.g., `myrouter-1.local`. Use an mDNS browser to scan for
an index, e.g., `example-1.local`. Use an mDNS browser to scan for
available devices on your LAN.
In some cases you may want to set the device's *domain name* as well.
This is handled the same way:
<pre class="cli"><code>admin@example:/config/> <b>edit system</b>
admin@example:/config/system/> <b>set hostname foo.example.com</b>
admin@example:/config/system/> <b>leave</b>
```
admin@host:/config/> edit system
admin@host:/config/system/> set hostname foo.example.com
admin@host:/config/system/> leave
admin@foo:/>
</code></pre>
```
Both host and domain name are stored in the system files `/etc/hosts`
and `/etc/hostname`. The latter is exclusively for the host name. The
@@ -401,11 +187,12 @@ built-in [`text-editor` command](cli/text-editor.md).
> See the next section for how to change the editor used to something
> you may be more familiar with.
<pre class="cli"><code>admin@example:/config/> <b>edit system</b>
admin@example:/config/system/> <b>text-editor motd-banner</b>
admin@example:/config/system/> <b>leave</b>
admin@example:/>
</code></pre>
```
admin@host:/config/> edit system
admin@host:/config/system/> text-editor motd-banner
admin@host:/config/system/> leave
admin@host:/>
```
Log out and log back in again to inspect the changes.
@@ -421,12 +208,13 @@ as the `text-editor` command:
To change the editor to GNU Nano:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit system</b>
admin@example:/config/system/> <b>set text-editor nano</b>
admin@example:/config/system/> <b>leave</b>
admin@example:/>
</code></pre>
```
admin@host:/> configure
admin@host:/config/> edit system
admin@host:/config/system/> set text-editor nano
admin@host:/config/system/> leave
admin@host:/>
```
> [!IMPORTANT]
> Configuration changes only take effect after issuing the `leave`
@@ -440,17 +228,18 @@ The system supports both static and dynamic (DHCP) DNS setup. The
locally configured (static) server is preferred over any acquired
from a DHCP client.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit system dns-resolver</b>
admin@example:/config/system/dns-resolver/> <b>set server google udp-and-tcp address 8.8.8.8</b>
admin@example:/config/system/dns-resolver/> <b>show</b>
```
admin@host:/> configure
admin@host:/config/> edit system dns-resolver
admin@host:/config/system/dns-resolver/> set server google udp-and-tcp address 8.8.8.8
admin@host:/config/system/dns-resolver/> show
server google {
udp-and-tcp {
address 8.8.8.8;
}
}
admin@example:/config/system/dns-resolver/> <b>leave</b>
</code></pre>
admin@host:/config/system/dns-resolver/> leave
```
It is also possible to configure resolver options like timeout and
retry attempts. See the YANG model for details, or use the built-in
@@ -467,15 +256,16 @@ help system in the CLI.
Below is an example configuration for enabling NTP with a specific
server and the `iburst` option for faster initial synchronization.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit system ntp</b>
admin@example:/config/system/ntp/> <b>set enabled</b>
admin@example:/config/system/ntp/> <b>set server ntp-pool</b>
admin@example:/config/system/ntp/> <b>set server ntp-pool udp address pool.ntp.org</b>
admin@example:/config/system/ntp/> <b>set server ntp-pool iburst</b>
admin@example:/config/system/ntp/> <b>set server ntp-pool prefer</b>
admin@example:/config/system/ntp/> <b>leave</b>
</code></pre>
```
admin@host:/> configure
admin@host:/config/> edit system ntp
admin@host:/config/system/ntp/> set enabled
admin@host:/config/system/ntp/> set server ntp-pool
admin@host:/config/system/ntp/> set server ntp-pool udp address pool.ntp.org
admin@host:/config/system/ntp/> set server ntp-pool iburst
admin@host:/config/system/ntp/> set server ntp-pool prefer
admin@host:/config/system/ntp/> leave
```
This configuration enables the NTP client and sets the NTP server to
`pool.ntp.org` with the `iburst` and `prefer` options. The `iburst`
@@ -495,38 +285,36 @@ The status for NTP sources is availble in YANG and accessable with
CLI/NETCONF/RESTCONF.
To view the sources being used by the NTP client, run:
<pre class="cli"><code>admin@example:/> <b>show ntp</b>
Mode : Client
Stratum : 3
Ref time (UTC) : Sat Jan 24 23:41:42 2026
<span class="header">ADDRESS MODE STATE STRATUM POLL</span>
147.78.228.41 server outlier 2 64s
192.168.0.1 server unusable 0 128s
176.126.86.247 server selected 2 64s
</code></pre>
```
admin@target:/> show ntp
ADDRESS MODE STATE STRATUM POLL-INTERVAL
192.168.1.1 server candidate 1 6
192.168.2.1 server candidate 1 6
192.168.3.1 server selected 1 6
```
### Show NTP Status
To check the status of NTP synchronization (only availble in CLI), use
the following command:
<pre class="cli"><code>admin@example:/> <b>show ntp tracking</b>
Reference ID : 176.126.86.247
Stratum : 3
Ref time (UTC) : Sat Jan 24 23:41:42 2026
System time : 0.000000 seconds slow of NTP time
Last offset : -454779.375000000 seconds
RMS offset : 454779.375000000 seconds
Frequency : 0.000 ppm slow
Residual freq : -26.383 ppm
Skew : 1000000.000 ppm
Root delay : 0.007395 seconds
Root dispersion : 39.181149 seconds
Update interval : 0.0 seconds
Leap status : Normal
</code></pre>
```
admin@host:/> show ntp tracking
Reference ID : C0248F86 (192.36.143.134)
Stratum : 2
Ref time (UTC) : Mon Oct 21 10:06:45 2024
System time : 0.000000001 seconds slow of NTP time
Last offset : -3845.151367188 seconds
RMS offset : 3845.151367188 seconds
Frequency : 4.599 ppm slow
Residual freq : +1293.526 ppm
Skew : 12.403 ppm
Root delay : 1.024467230 seconds
Root dispersion : 0.273462683 seconds
Update interval : 0.0 seconds
Leap status : Normal
admin@host:/>
```
This output provides detailed information about the NTP status, including
reference ID, stratum, time offsets, frequency, and root delay.
@@ -539,4 +327,3 @@ reference ID, stratum, time offsets, frequency, and root delay.
[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://linux.die.net/man/1/mkpasswd
+70 -61
View File
@@ -28,13 +28,14 @@ IPv6 tunnels in two modes:
A basic GRE tunnel for routing between two sites:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface gre0</b>
admin@example:/config/interface/gre0/> <b>set gre local 192.168.3.1 remote 192.168.3.2</b>
admin@example:/config/interface/gre0/> <b>set ipv4 address 10.255.0.1 prefix-length 30</b>
admin@example:/config/interface/gre0/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> edit interface gre0
admin@example:/config/interface/gre0/> set gre local 192.168.3.1 remote 192.168.3.2
admin@example:/config/interface/gre0/> set ipv4 address 10.255.0.1 prefix-length 30
admin@example:/config/interface/gre0/> leave
admin@example:/>
</code></pre>
```
This creates a Layer 3 tunnel between 192.168.3.1 and 192.168.3.2 using
the outer IP addresses, with the tunnel itself using 10.255.0.0/30 for
@@ -44,16 +45,17 @@ the inner IP addressing.
GRETAP tunnels operate at Layer 2, allowing bridging across the tunnel:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface gretap0</b>
admin@example:/config/interface/gretap0/> <b>set type gretap</b>
admin@example:/config/interface/gretap0/> <b>set gre local 192.168.3.1 remote 192.168.3.2</b>
admin@example:/config/interface/gretap0/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> edit interface gretap0
admin@example:/config/interface/gretap0/> set type gretap
admin@example:/config/interface/gretap0/> set gre local 192.168.3.1 remote 192.168.3.2
admin@example:/config/interface/gretap0/> leave
admin@example:/>
</code></pre>
```
GRETAP interfaces can be added to a bridge, bridging local and remote Ethernet
segments. See the [Bridge Configuration](bridging.md)
segments. See the [Bridge Configuration](networking.md#bridging)
for more on bridges.
### OSPF over GRE
@@ -67,35 +69,37 @@ exchange routes.
**Site A configuration:**
<pre class="cli"><code>admin@siteA:/> <b>configure</b>
admin@siteA:/config/> <b>edit interface gre0</b>
admin@siteA:/config/interface/gre0/> <b>set gre local 203.0.113.1 remote 203.0.113.2</b>
admin@siteA:/config/interface/gre0/> <b>set ipv4 address 10.255.0.1 prefix-length 30</b>
admin@siteA:/config/interface/gre0/> <b>set ipv4 forwarding</b>
admin@siteA:/config/interface/gre0/> <b>end</b>
admin@siteA:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@siteA:/config/routing/…/ospf/> <b>set area 0.0.0.0 interface gre0</b>
admin@siteA:/config/routing/…/ospf/> <b>leave</b>
```
admin@siteA:/> configure
admin@siteA:/config/> edit interface gre0
admin@siteA:/config/interface/gre0/> set gre local 203.0.113.1 remote 203.0.113.2
admin@siteA:/config/interface/gre0/> set ipv4 address 10.255.0.1 prefix-length 30
admin@siteA:/config/interface/gre0/> set ipv4 forwarding
admin@siteA:/config/interface/gre0/> end
admin@siteA:/config/> edit routing control-plane-protocol ospfv2 name default ospf
admin@siteA:/config/routing/…/ospf/> set area 0.0.0.0 interface gre0
admin@siteA:/config/routing/…/ospf/> leave
admin@siteA:/>
</code></pre>
```
**Site B configuration:**
<pre class="cli"><code>admin@siteB:/> <b>configure</b>
admin@siteB:/config/> <b>edit interface gre0</b>
admin@siteB:/config/interface/gre0/> <b>set gre local 203.0.113.2 remote 203.0.113.1</b>
admin@siteB:/config/interface/gre0/> <b>set ipv4 address 10.255.0.2 prefix-length 30</b>
admin@siteB:/config/interface/gre0/> <b>set ipv4 forwarding</b>
admin@siteB:/config/interface/gre0/> <b>end</b>
admin@siteB:/config/> <b>edit routing control-plane-protocol ospfv2 name default ospf</b>
admin@siteB:/config/routing/…/ospf/> <b>set area 0.0.0.0 interface gre0</b>
admin@siteB:/config/routing/…/ospf/> <b>leave</b>
```
admin@siteB:/> configure
admin@siteB:/config/> edit interface gre0
admin@siteB:/config/interface/gre0/> set gre local 203.0.113.2 remote 203.0.113.1
admin@siteB:/config/interface/gre0/> set ipv4 address 10.255.0.2 prefix-length 30
admin@siteB:/config/interface/gre0/> set ipv4 forwarding
admin@siteB:/config/interface/gre0/> end
admin@siteB:/config/> edit routing control-plane-protocol ospfv2 name default ospf
admin@siteB:/config/routing/…/ospf/> set area 0.0.0.0 interface gre0
admin@siteB:/config/routing/…/ospf/> leave
admin@siteB:/>
</code></pre>
```
Once configured, OSPF will establish a neighbor relationship through the
tunnel and exchange routes between the sites. For more info on OSPF
configuration, see [OSPFv2 Routing](routing.md#ospfv2-routing).
configuration, see [OSPFv2 Routing](networking.md#ospfv2-routing).
> [!NOTE]
> Consider adjusting MTU on the tunnel interface to account for GRE
@@ -114,10 +118,11 @@ The TTL setting controls the Time To Live value for the outer tunnel packets.
By default, tunnels use a fixed TTL of 64, which allows packets to traverse
multiple hops between tunnel endpoints.
<pre class="cli"><code>admin@example:/config/> <b>edit interface gre0</b>
admin@example:/config/interface/gre0/> <b>set gre ttl 255</b>
admin@example:/config/interface/gre0/> <b>leave</b>
</code></pre>
```
admin@example:/config/> edit interface gre0
admin@example:/config/interface/gre0/> set gre ttl 255
admin@example:/config/interface/gre0/> leave
```
Valid values are 1-255, or the special value `inherit` which copies the TTL
from the encapsulated packet.
@@ -131,10 +136,11 @@ from the encapsulated packet.
The ToS setting controls QoS marking for tunnel traffic:
<pre class="cli"><code>admin@example:/config/> <b>edit interface gre0</b>
admin@example:/config/interface/gre0/> <b>set gre tos 0x10</b>
admin@example:/config/interface/gre0/> <b>leave</b>
</code></pre>
```
admin@example:/config/> edit interface gre0
admin@example:/config/interface/gre0/> set gre tos 0x10
admin@example:/config/interface/gre0/> leave
```
Valid values are 0-255 for fixed ToS/DSCP marking, or `inherit` (default)
to copy the ToS value from the encapsulated packet.
@@ -145,10 +151,11 @@ The `pmtu-discovery` setting can be used to control the Path MTU Discovery on
GRE tunnels. When enabled (default), the tunnel respects the Don't Fragment
(DF) bit and performs PMTU discovery:
<pre class="cli"><code>admin@example:/config/> <b>edit interface gre0</b>
admin@example:/config/interface/gre0/> <b>set gre pmtudisc false</b>
admin@example:/config/interface/gre0/> <b>leave</b>
</code></pre>
```
admin@example:/config/> edit interface gre0
admin@example:/config/interface/gre0/> set gre pmtudisc false
admin@example:/config/interface/gre0/> leave
```
Disabling PMTU discovery may be necessary in networks with broken ICMP
filtering but can lead to suboptimal performance and fragmentation.
@@ -168,14 +175,15 @@ Infix supports both IPv4 and IPv6 for VXLAN tunnel endpoints.
> If you name your VXLAN interface `vxlanN`, where `N` is a number, the
> CLI infers the interface type automatically.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface vxlan100</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan local 192.168.3.1</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan remote 192.168.3.2</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan vni 100</b>
admin@example:/config/interface/vxlan100/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> edit interface vxlan100
admin@example:/config/interface/vxlan100/> set vxlan local 192.168.3.1
admin@example:/config/interface/vxlan100/> set vxlan remote 192.168.3.2
admin@example:/config/interface/vxlan100/> set vxlan vni 100
admin@example:/config/interface/vxlan100/> leave
admin@example:/>
</code></pre>
```
The VNI uniquely identifies the VXLAN segment and must match on both
tunnel endpoints.
@@ -185,15 +193,16 @@ tunnel endpoints.
The default VXLAN UDP destination port is 4789 (IANA assigned). In some
cases you may need to use a different port:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface vxlan100</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan local 192.168.3.1</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan remote 192.168.3.2</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan vni 100</b>
admin@example:/config/interface/vxlan100/> <b>set vxlan remote-port 8472</b>
admin@example:/config/interface/vxlan100/> <b>leave</b>
```
admin@example:/> configure
admin@example:/config/> edit interface vxlan100
admin@example:/config/interface/vxlan100/> set vxlan local 192.168.3.1
admin@example:/config/interface/vxlan100/> set vxlan remote 192.168.3.2
admin@example:/config/interface/vxlan100/> set vxlan vni 100
admin@example:/config/interface/vxlan100/> set vxlan remote-port 8472
admin@example:/config/interface/vxlan100/> leave
admin@example:/>
</code></pre>
```
The remote-port setting allows interoperability with systems using
non-standard VXLAN ports.
+102 -80
View File
@@ -8,14 +8,16 @@ 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`).
<pre class="cli"><code>admin@example:/> <b>show software</b>
Boot order : primary secondary net
```
admin@example:/> show software
BOOT ORDER
primary secondary net
<span class="header">NAME STATE VERSION DATE </span>
primary booted v25.01.0 2025-04-25T10:15:00+00:00
secondary inactive v25.01.0 2025-04-25T10:07:20+00:00
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:/>
</code></pre>
```
YANG support for upgrading Infix, inspecting and _modifying_ the
boot-order, is defined in [infix-system-software][2].
@@ -39,47 +41,52 @@ valid values.
Example: View current boot order and change it:
<pre class="cli"><code>admin@example:/> <b>show boot-order</b>
```
admin@example:/> show boot-order
primary secondary net
admin@example:/> <b>set boot-order secondary primary net</b>
admin@example:/> <b>show boot-order</b>
admin@example:/> set boot-order secondary primary net
admin@example:/> show boot-order
secondary primary net
admin@example:/>
</code></pre>
```
Example: Set boot order to only try primary partition:
<pre class="cli"><code>admin@example:/> <b>show boot-order</b>
```
admin@example:/> show boot-order
secondary primary net
admin@example:/> <b>set boot-order primary</b>
admin@example:/> <b>show boot-order</b>
admin@example:/> set boot-order primary
admin@example:/> show boot-order
primary
admin@example:/>
</code></pre>
```
Example: Using tab-completion (press TAB to see available options):
<pre class="cli"><code>admin@example:/> <b>set boot-order </b><kbd>TAB</kbd>
```
admin@example:/> set boot-order <TAB>
net primary secondary
admin@example:/> <b>set boot-order secondary </b><kbd>TAB</kbd>
admin@example:/> set boot-order secondary <TAB>
net primary secondary
admin@example:/> <b>set boot-order secondary primary</b>
admin@example:/> <b>show boot-order</b>
admin@example:/> set boot-order secondary primary
admin@example:/> show boot-order
secondary primary
admin@example:/>
</code></pre>
```
The new boot order takes effect on the next reboot and can be verified
with `show boot-order` or `show software`:
<pre class="cli"><code>admin@example:/> <b>show software</b>
Boot order : secondary primary
```
admin@example:/> show software
BOOT ORDER
secondary primary
<span class="header">NAME STATE VERSION DATE </span>
primary booted v25.01.0 2025-04-25T10:15:00+00:00
secondary inactive v25.01.0 2025-04-25T10:07:20+00:00
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:/>
</code></pre>
```
> [!NOTE]
> The boot order is automatically updated when performing an upgrade.
@@ -120,28 +127,27 @@ configuration before performing an upgrade. The backup is useful if the
upgrade fails, and makes a later [downgrade](#downgrading) a smoother
process.
<pre class="cli"><code>admin@example:/> <b>dir /cfg</b>
```
admin@example:/> dir /cfg
/cfg directory
backup/ ssl/ startup-config.cfg
admin@example:/> <b>copy /cfg/startup-config.cfg /cfg/v25.01.0-startup-config.cfg</b>
admin@example:/> <b>dir /cfg</b>
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:/>
</code></pre>
admin@example:/>
```
*Upgrade:* Here the image *pkg bundle* was made available via TFTP.
<pre class="cli"><code>admin@example:/> <b>upgrade tftp://198.18.117.1/infix-aarch64-25.03.1.pkg</b>
```
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.
...
40% Checking slot rootfs.1 (secondary)
46% Checking slot rootfs.1 (secondary) done.
...
98% Copying image to rootfs.1
99% Copying image to rootfs.1
@@ -150,13 +156,14 @@ installing
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.03.1.pkg` succeeded
admin@example:/>
</code></pre>
```
*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.
<pre class="cli"><code>admin@example:/> <b>reboot</b>
```
admin@example:/> reboot
[ OK ] Stopping Static routing daemon
[ OK ] Stopping Zebra routing daemon
...
@@ -166,7 +173,7 @@ of startup configuration if applicable.
[ OK ] Starting Status daemon
Infix OS — Immutable.Friendly.Secure v25.03.1 (ttyS0)
example login: <b>admin</b>
example login: admin
Password:
.-------.
| . . | Infix OS — Immutable.Friendly.Secure
@@ -175,18 +182,19 @@ Password:
Run the command 'cli' for interactive OAM
admin@example:~$ <b>cli</b>
admin@example:~$ cli
See the 'help' command for an introduction to the system
admin@example:/> <b>show software</b>
Boot order : secondary primary net
admin@example:/> show software
BOOT ORDER
secondary primary net
<span class="header">NAME STATE VERSION DATE </span>
primary inactive v25.01.0 2025-04-25T10:15:00+00:00
secondary booted v25.03.1 2025-04-25T10:24:31+00:00
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:/>
</code></pre>
```
As shown, the *boot order* has been updated, so that *secondary* is
now the preferred boot source.
@@ -209,18 +217,20 @@ numbering). The startup configuration is migrated to `1.5`
definitions and stored, while a backup previous startup configuration
is stored in directory `/cfg/backup/`.
<pre class="cli"><code>admin@example:/> <b>dir /cfg/backup/</b>
```
admin@example:/> dir /cfg/backup/
/cfg/backup/ directory
startup-config-1.4.cfg
admin@example:/>
</code></pre>
```
The modifications made to the startup configuration can be viewed by
comparing the files from the *shell*. An example is shown below.
<pre class="cli"><code>admin@example:/> <b>exit</b>
admin@example:~$ <b>diff /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg</b>
```
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
...
@@ -234,7 +244,7 @@ admin@example:~$ <b>diff /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.
+ "version": "1.5"
...
admin@example:~$
</code></pre>
```
## Downgrading
@@ -249,14 +259,16 @@ 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.
<pre class="cli"><code>admin@example:/> <b>show software</b>
Boot order : primary secondary net
```
admin@example:/> show software
BOOT ORDER
primary secondary net
<span class="header">NAME STATE VERSION DATE </span>
primary booted v25.03.1 2025-04-25T11:36:26+00:00
secondary inactive v25.03.1 2025-04-25T10:24:31+00:00
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:/>
</code></pre>
```
### With Backup `startup-config`
@@ -280,22 +292,24 @@ running Infix v25.01.0 on the unit. See section [Upgrading](#upgrading)
above for more information. In the following example, there is a backup
file available named `v25.01.0-startup-config.cfg`:
<pre class="cli"><code>admin@example:/> <b>dir /cfg</b>
```
admin@example:/> dir /cfg
/cfg directory
backup/ ssl/ startup-config.cfg v25.01.0-startup-config.cfg
admin@example:/>
</code></pre>
admin@example:/>
```
The alternative is to use a startup config implicitly backed up by the
system as part of [Configuration Migration](#configuration-migration).
<pre class="cli"><code>admin@example:/> <b>dir /cfg/backup/</b>
```
admin@example:/> dir /cfg/backup/
/cfg/backup/ directory
startup-config-1.4.cfg
admin@example:/>
</code></pre>
```
> [!CAUTION]
> Using a backup configuration file stored when the unit was running the
@@ -316,7 +330,8 @@ config*.
*Use `upgrade` command to downgrade:*
<pre class="cli"><code>admin@example:/> <b>upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg</b>
```
admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
0% Installing
0% Determining slot states
@@ -327,32 +342,35 @@ installing
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>
</code></pre>
```
*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.
<pre class="cli"><code>admin@example:/> <b>copy /cfg/v25.01.0-startup-config.cfg /cfg/startup-config.cfg</b>
Overwrite existing file /cfg/startup-config.cfg (y/N)? <b>y</b>
```
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:/>
</code></pre>
```
An alternative is to use a backup file stored when the system
conducted a [configuration migration](#configuration-migration). See
the *caution* note above.
<pre class="cli"><code>admin@example:/> <b>copy /cfg/backup/startup-config-1.4.cfg /cfg/startup-config.cfg</b>
Overwrite existing file /cfg/startup-config.cfg (y/N)? <b>y</b>
```
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:/>
</code></pre>
```
*Reboot:*
The unit will come up with the applied backup configuration.
<pre class="cli"><code>admin@example:/> <b>reboot</b>
```
admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
@@ -366,7 +384,7 @@ The unit will come up with the applied backup configuration.
Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)
example login:
</code></pre>
```
> [!NOTE]
> If the unit despite these measures ends up in *failure config*, see
@@ -385,7 +403,8 @@ its default login credentials[^1].
*Use `upgrade` command to downgrade:*
<pre class="cli"><code>admin@example:/> <b>upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg</b>
```
admin@example:/> upgrade tftp://198.18.117.1/infix-aarch64-25.01.0.pkg
installing
0% Installing
0% Determining slot states
@@ -396,7 +415,7 @@ installing
100% Installing done.
Installing `tftp://198.18.117.1/infix-aarch64-25.01.0.pkg` succeeded
admin@example:/>
</code></pre>
```
*Reboot:*
@@ -407,7 +426,8 @@ config][3]. This is what is seen on the console when this situation
occurs. Note that the login prompt displays `failed` as part of the
*hostname*.
<pre class="cli"><code>admin@example:/> <b>reboot</b>
```
admin@example:/> reboot
[ OK ] Saving system clock to file
[ OK ] Stopping Software update service
[ OK ] Stopping Status daemon
@@ -424,30 +444,32 @@ Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)
ERROR: Corrupt startup-config, system has reverted to default login credentials
failed-00-00-00 login:
</code></pre>
```
To remedy a situation like this, you can login with the unit's *default
login credentials*, preferrably via a [console port][4].
The unit's default credentials are typically printed on a sticker on
the unit.
<pre class="cli"><code>failed-00-00-00 login: <b>admin</b>
```
failed-00-00-00 login: admin
Password:
Run the command 'cli' for interactive OAM
admin@failed-00-00-00:~$
</code></pre>
```
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.
<pre class="cli"><code>admin@failed-00-00-00:~$ <b>factory</b>
Factory reset device (y/N)? <b>y</b>
```
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)? <b>y</b>
Reboot now to perform reset, (y/N)? y
[ OK ] Saving system time (UTC) to RTC
[ OK ] Stopping mDNS alias advertiser
...
@@ -463,7 +485,7 @@ Please press Enter to activate this console.
Infix OS — Immutable.Friendly.Secure v25.01.0 (ttyS0)
example login:
</code></pre>
```
Continued configuration is done as with any unit after factory reset.
+4 -4
View File
@@ -18,11 +18,11 @@ QEMU
> relevant Qemu packages are pulled in as well. This trick, installing
> [virt-manager][virt], helps set up Qemu networking on your system.
A virtualized Infix x86_64 instance can be launched from a Linux system,
with [Qemu][] installed, by issuing:
A virtualized Infix x86_64 instance can easily be launched from a Linux
system, with [Qemu][] installed, by issuing:
```
$ ./qemu/run.sh
$ ./qemu.sh
...
```
@@ -35,7 +35,7 @@ $ make run
```
To change settings, e.g. networking, <kbd>make run-menuconfig</kbd>, or
from a pre-built Infix release tarball, using <kbd>./qemu/run.sh -c</kbd>
from a pre-built Infix release tarball, using <kbd>./qemu.sh -c</kbd>
The Infix test suite is built around Qemu and [Qeneth][qeth], see:
-424
View File
@@ -1,424 +0,0 @@
# WireGuard VPN
> [!NOTE]
> For a general introduction to VPN concepts and deployment models, see
> [VPN Configuration](vpn.md).
WireGuard is a modern, high-performance VPN protocol that uses state-of-the-art
cryptography. It is significantly simpler and faster than traditional VPN
solutions like IPsec or OpenVPN, while maintaining strong security guarantees.
Key features of WireGuard:
- **Simple Configuration:** Minimal settings required compared to IPsec
- **High Performance:** Runs in kernel space with efficient cryptography
- **Strong Cryptography:** Uses Curve25519, ChaCha20, Poly1305, and BLAKE2
- **Roaming Support:** Seamlessly handles endpoint IP address changes
- **Dual-Stack:** Supports IPv4 and IPv6 for both tunnel endpoints and traffic
> [!IMPORTANT]
> When issuing `leave` to activate your changes, remember to also save
> your settings, `copy running-config startup-config`. See the [CLI
> Introduction](cli/introduction.md) for a background.
## Key Management
WireGuard uses public-key cryptography similar to SSH. Each WireGuard interface
requires a private key, and each peer is identified by its public key.
**Generate a WireGuard key pair using the `wg` command:**
```bash
admin@example:~$ wg genkey | tee privatekey | wg pubkey > publickey
admin@example:~$ cat privatekey
aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=
admin@example:~$ cat publickey
bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=
```
This generates a private key, saves it to `privatekey`, derives the public key,
and saves it to `publickey`.
**Import the private key into the keystore:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit keystore asymmetric-key wg-site-a</b>
admin@example:/config/keystore/asymmetric-key/wg-site-a/> <b>set public-key-format x25519-public-key-format</b>
admin@example:/config/keystore/asymmetric-key/wg-site-a/> <b>set private-key-format x25519-private-key-format</b>
admin@example:/config/keystore/asymmetric-key/wg-site-a/> <b>set public-key bN1CwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP6KsrCwZ1lTP=</b>
admin@example:/config/keystore/asymmetric-key/wg-site-a/> <b>set private-key aMqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP5JrqBvZqkSP=</b>
admin@example:/config/keystore/asymmetric-key/wg-site-a/> <b>leave</b>
admin@example:/>
</code></pre>
**Import peer public keys into the truststore:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit truststore public-key-bag wg-peers public-key peer-b</b>
admin@example:/config/truststore/…/peer-b/> <b>set public-key-format x25519-public-key-format</b>
admin@example:/config/truststore/…/peer-b/> <b>set public-key PEER_PUBLIC_KEY_HERE</b>
admin@example:/config/truststore/…/peer-b/> <b>leave</b>
admin@example:/>
</code></pre>
> [!IMPORTANT]
> Keep private keys secure! Never share your private key. Only exchange
> public keys with peers. Delete the `privatekey` file after importing it
> into the keystore.
## Point-to-Point Configuration
> [!TIP]
> If you name your WireGuard interface `wgN`, where `N` is a number, the
> CLI infers the interface type automatically.
A basic WireGuard tunnel between two sites:
**Site A configuration:**
<pre class="cli"><code>admin@siteA:/> <b>configure</b>
admin@siteA:/config/> <b>edit interface wg0</b>
admin@siteA:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@siteA:/config/interface/wg0/> <b>set wireguard private-key wg-site-a</b>
admin@siteA:/config/interface/wg0/> <b>set ipv4 address 10.0.0.1 prefix-length 24</b>
admin@siteA:/config/interface/wg0/> <b>edit wireguard peer wg-peers peer-b</b>
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> <b>set endpoint 203.0.113.2</b>
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> <b>set endpoint-port 51820</b>
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> <b>set allowed-ips 10.0.0.2/32</b>
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> <b>set persistent-keepalive 25</b>
admin@siteA:/config/interface/…/wg-peers/peer/peer-b/> <b>leave</b>
admin@siteA:/>
</code></pre>
**Site B configuration:**
<pre class="cli"><code>admin@siteB:/> <b>configure</b>
admin@siteB:/config/> <b>edit interface wg0</b>
admin@siteB:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@siteB:/config/interface/wg0/> <b>set wireguard private-key wg-site-b</b>
admin@siteB:/config/interface/wg0/> <b>set ipv4 address 10.0.0.2 prefix-length 24</b>
admin@siteB:/config/interface/wg0/> <b>edit wireguard peer wg-peers peer-a</b>
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> <b>set endpoint 203.0.113.1</b>
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> <b>set endpoint-port 51820</b>
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> <b>set allowed-ips 10.0.0.1/32</b>
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> <b>set persistent-keepalive 25</b>
admin@siteB:/config/interface/…/wg-peers/peer/peer-a/> <b>leave</b>
admin@siteB:/>
</code></pre>
This creates an encrypted tunnel with Site A at 10.0.0.1 and Site B at 10.0.0.2.
## Understanding Allowed IPs
The `allowed-ips` setting in WireGuard serves two critical purposes:
1. **Ingress Filtering:** Only packets with source IPs in the allowed list
are accepted from the peer
2. **Cryptokey Routing:** Determines which peer receives outbound packets
for a given destination
Think of `allowed-ips` as a combination of firewall rules and routing table.
![WireGuard Keys and Allowed IPs](img/wireguard-allowed-ips.svg)
*Figure: WireGuard key exchange and allowed-ips configuration between two peers*
For a simple point-to-point tunnel, you typically allow only the peer's
tunnel IP address (e.g., `10.0.0.2/32`). For site-to-site VPNs connecting
entire networks, include the remote network prefixes:
<pre class="cli"><code>admin@example:/config/interface/…/wg-peers/peer/peer-a/> <b>set allowed-ips 10.0.0.2/32</b>
admin@example:/config/interface/…/wg-peers/peer/peer-a/> <b>set allowed-ips 192.168.2.0/24</b>
</code></pre>
This allows traffic to/from the peer at 10.0.0.2 and routes traffic destined
for 192.168.2.0/24 through this peer.
> [!NOTE]
> When routing traffic to networks behind WireGuard peers, you also need
> to configure static routes pointing to the WireGuard interface. See
> [Static Routes](routing.md) for more information.
## Peer Configuration and Key Bags
WireGuard peer configuration supports a two-level hierarchy that allows
efficient management of multiple peers with shared settings.
**Public Key Bags** group related peers together (e.g., all mobile clients,
all branch offices) and allow you to configure default settings that apply
to all peers in the bag. Individual peers can then override these defaults
when needed.
Settings that support bag-level defaults and per-peer overrides:
- `endpoint` - Remote peer's IP address
- `endpoint-port` - Remote peer's UDP port (defaults to 51820 at bag level)
- `persistent-keepalive` - Keepalive interval in seconds
- `preshared-key` - Optional pre-shared key for additional quantum resistance
- `allowed-ips` - IP addresses allowed to/from this peer
> [!IMPORTANT]
> **Key Bag Configuration Rules:**
> - **Single key in bag:** You can use bag-level settings (endpoint, allowed-ips, etc.)
> without specifying individual peer configurations. All settings apply to that one peer.
> - **Multiple keys in bag:** You MUST provide individual `peer` configuration for
> each key in the bag. Settings like `endpoint` and `allowed-ips` must be unique
> per peer and cannot be shared at the bag level when multiple peers exist.
>
> This prevents configuration errors where multiple peers would incorrectly share
> the same endpoint address or allowed-ips ranges.
**Example with bag-level defaults:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface wg0</b>
admin@example:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@example:/config/interface/wg0/> <b>set wireguard private-key wg-key</b>
admin@example:/config/interface/wg0/> <b>set ipv4 address 10.0.0.1 prefix-length 24</b>
# Configure defaults for all peers in the 'branch-offices' bag
admin@example:/config/interface/wg0/> <b>edit wireguard peers branch-offices</b>
admin@example:/config/interface/…/wireguard/peers/branch-offices/> <b>set endpoint-port 51820</b>
admin@example:/config/interface/…/wireguard/peers/branch-offices/> <b>set persistent-keepalive 25</b>
admin@example:/config/interface/…/wireguard/peers/branch-offices/> <b>end</b>
# Configure peer-specific settings (inherits endpoint-port and keepalive from bag)
admin@example:/config/interface/…/wireguard/peers/branch-offices/> <b>edit peer office-east</b>
admin@example:/config/interface/…/branch-offices/peer/office-east/> <b>set endpoint 203.0.113.10</b>
admin@example:/config/interface/…/branch-offices/peer/office-east/> <b>set allowed-ips 10.0.0.10/32</b>
admin@example:/config/interface/…/branch-offices/peer/office-east/> <b>set allowed-ips 192.168.10.0/24</b>
admin@example:/config/interface/…/branch-offices/peer/office-east/> <b>end</b>
# Another peer with an override for persistent-keepalive
admin@example:/config/interface/…/wireguard/peers/branch-offices/> <b>edit peer office-west</b>
admin@example:/config/interface/…/branch-offices/peer/office-west/> <b>set endpoint 203.0.113.20</b>
admin@example:/config/interface/…/branch-offices/peer/office-west/> <b>set allowed-ips 10.0.0.20/32</b>
admin@example:/config/interface/…/branch-offices/peer/office-west/> <b>set allowed-ips 192.168.20.0/24</b>
admin@example:/config/interface/…/branch-offices/peer/office-west/> <b>set persistent-keepalive 10</b>
admin@example:/config/interface/…/branch-offices/peer/office-west/> <b>leave</b>
admin@example:/>
</code></pre>
In this example:
- Both peers inherit `endpoint-port 51820` and `persistent-keepalive 25` from the bag
- `office-west` overrides the keepalive to 10 seconds while `office-east` uses the default 25
- Each peer has its own `endpoint` and `allowed-ips` configuration
This approach simplifies management when you have many peers with similar
configurations - set the common defaults once at the bag level, then only
specify per-peer differences.
## Site-to-Site VPN
![Site-to-Site VPN Topology](img/vpn-site-to-site.svg)
*Figure: Site-to-Site VPN connecting two office networks*
A site-to-site VPN connects entire networks across locations, creating a unified
private network over the internet. This allows devices in one location to
seamlessly access resources in another as if they were on the same local network.
This is the point-to-point configuration shown earlier, extended with routing
to allow access to networks behind each peer. Configure the WireGuard tunnel
as shown in [Point-to-Point Configuration](#point-to-point-configuration),
then add the remote network to `allowed-ips` and configure static routes.
## Road Warrior VPN
![Road Warrior VPN Topology](img/vpn-roadwarrior.svg)
*Figure: Mobile clients connecting to corporate network*
For mobile clients or peers without fixed IPs, omit the `endpoint` setting.
WireGuard learns the peer's endpoint from authenticated incoming packets:
<pre class="cli"><code>admin@hub:/> <b>configure</b>
admin@hub:/config/> <b>edit interface wg0 wireguard peers wg-peers peer mobile-client</b>
admin@hub:/config/interface/…/wg-peers/peer/mobile-client/> <b>set allowed-ips 10.0.0.10/32</b>
admin@hub:/config/interface/…/wg-peers/peer/mobile-client/> <b>leave</b>
admin@hub:/>
</code></pre>
The mobile client configures the hub's endpoint normally. The hub learns
and tracks the mobile client's changing IP address automatically.
## Hub-and-Spoke Topology
![Hub-and-Spoke VPN Topology](img/vpn-hub-spoke.svg)
*Figure: Hub-and-Spoke topology with central hub routing traffic between spokes*
WireGuard excels at hub-and-spoke (star) topologies where multiple remote
sites connect to a central hub.
**Hub configuration:**
<pre class="cli"><code>admin@hub:/> <b>configure</b>
admin@hub:/config/> <b>edit interface wg0</b>
admin@hub:/config/interface/wg0/> <b>set ipv4 address 10.0.0.1 prefix-length 24</b>
admin@hub:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@hub:/config/interface/wg0/> <b>set wireguard private-key wg-hub</b>
admin@hub:/config/interface/wg0/> <b>edit wireguard peers wg-peers</b>
# Spoke 1
admin@hub:/config/interface/…/wireguard/peers/wg-peers/> <b>edit peer spoke1</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> <b>set allowed-ips 10.0.0.2/32</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> <b>set allowed-ips 192.168.1.0/24</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke1/> <b>end</b>
# Spoke 2
admin@hub:/config/interface/…/wireguard/peers/wg-peers/> <b>edit peer spoke2</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> <b>set allowed-ips 10.0.0.3/32</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> <b>set allowed-ips 192.168.2.0/24</b>
admin@hub:/config/interface/…/wg-peers/peer/spoke2/> <b>leave</b>
# Add routes for spoke networks
admin@hub:/> <b>configure</b>
admin@hub:/config/> <b>edit routing control-plane-protocol static name default</b>
admin@hub:/config/routing/…/static/name/default/> <b>set ipv4 route 192.168.1.0/24 wg0</b>
admin@hub:/config/routing/…/static/name/default/> <b>set ipv4 route 192.168.2.0/24 wg0</b>
admin@hub:/config/routing/…/static/name/default/> <b>leave</b>
admin@hub:/>
</code></pre>
**Spoke 1 configuration:**
<pre class="cli"><code>admin@spoke1:/> <b>configure</b>
admin@spoke1:/config/> <b>edit interface wg0</b>
admin@spoke1:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@spoke1:/config/interface/wg0/> <b>set wireguard private-key wg-spoke1</b>
admin@spoke1:/config/interface/wg0/> <b>set ipv4 address 10.0.0.2 prefix-length 24</b>
admin@spoke1:/config/interface/wg0/> <b>edit wireguard peers wg-peers peer hub</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set endpoint 203.0.113.1</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set endpoint-port 51820</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set allowed-ips 10.0.0.1/32</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set allowed-ips 10.0.0.3/32</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set allowed-ips 192.168.0.0/24</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set allowed-ips 192.168.2.0/24</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>set persistent-keepalive 25</b>
admin@spoke1:/config/interface/…/wg-peers/peer/hub/> <b>leave</b>
admin@spoke1:/> <b>configure</b>
admin@spoke1:/config/> <b>edit routing control-plane-protocol static name default</b>
admin@spoke1:/config/routing/…/static/name/default/> <b>set ipv4 route 192.168.0.0/24 wg0</b>
admin@spoke1:/config/routing/…/static/name/default/> <b>set ipv4 route 192.168.2.0/24 wg0</b>
admin@spoke1:/config/routing/…/static/name/default/> <b>leave</b>
admin@spoke1:/>
</code></pre>
This configuration allows Spoke 1 to reach both the hub network (192.168.0.0/24)
and Spoke 2's network (192.168.2.0/24) via the hub, enabling spoke-to-spoke
communication through the central hub.
## Persistent Keepalive
The `persistent-keepalive` setting sends periodic packets to keep the tunnel
active through NAT devices and firewalls:
<pre class="cli"><code>admin@example:/config/interface/…/wg-peers/peer/hub/> <b>set persistent-keepalive 25</b>
</code></pre>
This is particularly important when:
- The peer is behind NAT
- Intermediate firewalls have connection timeouts
- You need the tunnel to remain ready for bidirectional traffic
A value of 25 seconds is recommended for most scenarios. Omit this setting
for peers with public static IPs that initiate connections.
> [!NOTE]
> Only the peer behind NAT needs `persistent-keepalive` configured. The
> peer with a public IP learns the NAT endpoint from incoming packets.
## IPv6 Endpoints
WireGuard fully supports IPv6 for tunnel endpoints:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface wg0</b>
admin@example:/config/interface/wg0/> <b>set wireguard listen-port 51820</b>
admin@example:/config/interface/wg0/> <b>set wireguard private-key wg-key</b>
admin@example:/config/interface/wg0/> <b>set ipv4 address 10.0.0.1 prefix-length 24</b>
admin@example:/config/interface/wg0/> <b>set ipv6 address fd00::1 prefix-length 64</b>
admin@example:/config/interface/wg0/> <b>edit wireguard peers wg-peers peer remote</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>set endpoint 2001:db8::2</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>set endpoint-port 51820</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>set allowed-ips 10.0.0.2/32</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>set allowed-ips fd00::2/128</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>leave</b>
admin@example:/>
</code></pre>
WireGuard can carry both IPv4 and IPv6 traffic regardless of whether the
tunnel endpoints use IPv4 or IPv6.
## Monitoring WireGuard Status
Check WireGuard interface status and peer connections:
<pre class="cli"><code>admin@example:/> <b>show interfaces</b>
wg0 wireguard UP 2 peers (1 up)
ipv4 10.0.0.1/24 (static)
ipv6 fd00::1/64 (static)
admin@example:/> <b>show interfaces wg0</b>
name : wg0
type : wireguard
index : 12
operational status : up
peers : 2
Peer 1:
status : UP
endpoint : 203.0.113.2:51820
latest handshake : 2025-12-09T10:23:45+0000
transfer tx : 125648 bytes
transfer rx : 98432 bytes
Peer 2:
status : DOWN
endpoint : 203.0.113.3:51820
latest handshake : 2025-12-09T09:15:22+0000
transfer tx : 45120 bytes
transfer rx : 32768 bytes
</code></pre>
The connection status shows `UP` if a handshake occurred within the last 3
minutes, indicating an active tunnel. The `latest handshake` timestamp shows
when the peers last successfully authenticated and exchanged keys.
## Post-Quantum Security (Preshared Keys)
WireGuard supports optional preshared keys (PSK) that add an extra layer of
symmetric encryption alongside Curve25519. This provides defense-in-depth
against future quantum computers that might break elliptic curve cryptography.
PSKs protect your data from "harvest now, decrypt later" attacks - adversaries
recording traffic today would still need the PSK even if they break Curve25519
later. However, peer authentication still relies on Curve25519, so PSKs don't
provide complete post-quantum security.
**Generate a preshared key using `wg genpsk`:**
```bash
admin@example:~$ wg genpsk > preshared.key
admin@example:~$ cat preshared.key
cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=
```
**Import the preshared key into the keystore:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit keystore symmetric-key wg-psk</b>
admin@example:/config/keystore/symmetric-key/wg-psk/> <b>set key-format wireguard-symmetric-key-format</b>
admin@example:/config/keystore/symmetric-key/wg-psk/> <b>set key cO2DxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2mUQ7LtsrDxZ2m=</b>
admin@example:/config/keystore/symmetric-key/wg-psk/> <b>end</b>
admin@example:/config/interface/wg0/> <b>edit wireguard peers wg-peers peer remote</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>set preshared-key wg-psk</b>
admin@example:/config/interface/…/wg-peers/peer/remote/> <b>leave</b>
admin@example:/>
</code></pre>
The preshared key must be securely shared between both peers and configured
on both sides.
> [!IMPORTANT]
> Preshared keys must be kept secret and exchanged through a secure channel,
> just like passwords. Delete the `preshared.key` file after importing it
> into both peer keystores.
-83
View File
@@ -1,83 +0,0 @@
# VPN Configuration
A Virtual Private Network (VPN) creates encrypted tunnels over public networks,
enabling secure communication between remote locations or users. Unlike plain
tunnels (GRE, VXLAN) that only provide encapsulation, VPNs add authentication
and encryption to protect data confidentiality and integrity.
## Configuring VPN
For detailed configuration instructions and examples, see:
- **[WireGuard VPN](vpn-wireguard.md)** - Complete guide to configuring
WireGuard tunnels, including site-to-site, road warrior, and hub-and-spoke
topologies.
## Understanding VPN Tunnels
VPN tunnels establish secure connections across untrusted networks by:
- **Authentication:** Verifying the identity of tunnel endpoints using
cryptographic keys or certificates
- **Encryption:** Protecting data confidentiality with strong ciphers
- **Integrity:** Detecting tampering through message authentication codes
This makes VPNs essential for connecting sites over the internet, enabling
remote access for mobile users, and securing traffic in untrusted environments.
### VPN Deployment Models
VPNs are typically deployed in one of several models:
**Site-to-Site VPN**
![Site-to-Site VPN Topology](img/vpn-site-to-site.svg)
*Figure: Site-to-Site VPN connecting two office networks*
Connects entire networks across locations, creating a unified private network
over the internet. Routers or firewalls at each site maintain persistent
tunnels, allowing seamless access between locations.
- Use case: Connecting branch offices to headquarters
- Characteristics: Always-on, connects networks not individual devices
- Example: Main office (192.168.1.0/24) ↔ Branch office (192.168.2.0/24)
**Remote Access VPN (Road Warrior)**
![Road Warrior VPN Topology](img/vpn-roadwarrior.svg)
*Figure: Mobile clients connecting to corporate network*
Enables individual users to securely access a private network from remote
locations. Clients initiate connections as needed from dynamic IP addresses.
- Use case: Remote employees accessing corporate resources
- Characteristics: On-demand, handles dynamic endpoints and roaming
- Example: Mobile laptop ↔ Corporate network
**Hub-and-Spoke VPN**
![Hub-and-Spoke VPN Topology](img/vpn-hub-spoke.svg)
*Figure: Hub-and-Spoke topology with central hub routing traffic between spokes*
A central hub connects to multiple remote sites (spokes), routing traffic
between them. Spokes don't connect directly to each other but communicate
through the hub.
- Use case: Central office connecting multiple remote locations
- Characteristics: Centralized control, simplified management
- Example: HQ ↔ (Branch A, Branch B, Branch C)
### VPN Protocol Comparison
Different VPN protocols offer varying trade-offs between security, performance,
and complexity:
| Protocol | Complexity | Performance | Use Case |
|------------|------------|-------------|---------------------------------|
| WireGuard | Simple | Very High | Modern deployments, all models |
| IPsec | Complex | High | Legacy systems, compliance reqs |
| OpenVPN | Moderate | Moderate | Maximum compatibility |
Infix supports WireGuard as its primary VPN solution, offering the best
balance of simplicity, security, and performance for modern networks.
+107 -436
View File
@@ -1,50 +1,14 @@
# Wi-Fi (Wireless LAN)
Infix includes comprehensive Wi-Fi support for both client (Station) and
Access Point modes. When a compatible Wi-Fi adapter is detected, the system
automatically creates a WiFi radio (PHY) in factory-config, that can
host virtual interfaces.
## Architecture Overview
Infix uses a two-layer WiFi architecture:
1. **WiFi Radio (PHY layer)**: Represents the physical wireless hardware
- Configured via `ietf-hardware` module
- Controls channel, transmit power, regulatory domain
- One radio can host multiple virtual interfaces
2. **WiFi Interface (Network layer)**: Virtual interface on a radio
- Configured via `infix-interfaces` module
- Can operate in Station (client) or Access Point mode
- Each interface references a parent radio
## Naming Conventions
Like other interface types in Infix, WiFi components follow naming conventions
that allow the CLI to automatically infer types:
| **Name Pattern** | **Type** | **Description** |
|------------------|-----------------|------------------------------------------|
| `radioN` | WiFi Radio | Hardware component for WiFi PHY |
| `wifiN` | WiFi Interface | Virtual WiFi interface on a radio |
Where `N` is a number (0, 1, 2, ...).
> [!TIP]
> Using these naming conventions simplifies configuration since type/class
> settings are automatically inferred. For example, creating a hardware
> component named `radio0` automatically sets its class to `wifi`, enabling
> the `wifi-radio` configuration container.
>
> **Note:** This inference only works with the CLI. Configuring WiFi over
> NETCONF or RESTCONF requires setting the class/type explicitly.
Infix includes built-in Wi-Fi client support for connecting to
wireless networks. When a compatible Wi-Fi adapter is detected, the
system automatically begins scanning for available networks.
## Current Limitations
- Only client mode is supported (no access point functionality)
- USB hotplug is not supported - adapters must be present at boot
- Interface naming may be inconsistent with multiple USB Wi-Fi adapters
- AP and Station modes cannot be mixed on the same radio
## Supported Wi-Fi Adapters
@@ -52,430 +16,137 @@ Wi-Fi support is primarily tested with Realtek chipset-based adapters.
### Known Working Chipsets
- Built-in Wi-Fi on Banana Pi BPi-R3
- Built-in Wi-Fi on Raspberry Pi 4/CM4
- Realtek:
- RTL8188CU
- RTL8188FU
- RTL8821CU
- RTL8821CU
- Other Realtek chipsets may work but are not guaranteed
Other Realtek chipsets may work but are not tested.
> [!NOTE]
> Some Realtek chipsets require proprietary drivers not included in the
> standard kernel.
>
> - Firmware requirements vary by chipset
> - Check kernel logs if your adapter is not detected
> [!NOTE] Some Realtek chipsets require proprietary drivers not included in the standard kernel
> Firmware requirements vary by chipset
> Check kernel logs if your adapter is not detected
### USB WiFi Dongles
## Configuration
USB WiFi dongles may be slow to initialize at boot due to firmware
loading. If your USB dongle is not detected reliably, configure a
`probe-timeout` on the radio to wait for the PHY:
Add a supported Wi-Fi network device. To verify that it has been
detected, look for `wifi0` in `show interface`
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit hardware component radio0 wifi-radio</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set probe-timeout 30</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>leave</b>
</code></pre>
```
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
lo loopback UP
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
e1 ethernet UP 02:00:00:00:00:01
ipv6 fe80::ff:fe00:1/64 (link-layer)
ipv6 fec0::ff:fe00:1/64 (link-layer)
wifi0 ethernet DOWN f0:09:0d:36:5f:86
wifi ssid: ------, signal: ------
This waits up to 30 seconds for the radio PHY to appear before creating
WiFi interfaces. If the PHY is not detected within the timeout, a dummy
interface is created as a placeholder, allowing IP configuration to proceed.
Reboot when the radio becomes available.
```
Add the new Wi-Fi interface to the configuration to start scanning.
```
admin@example:/config/> set interface wifi0
admin@example:/config/> leave
```
Now the system will now start scanning in the background. To
see the result read the operational datastore for interface `wifi0` or
use the CLI
## Radio Configuration
Before configuring WiFi interfaces, you must first configure the WiFi radio.
Radios are automatically discovered and named `radio0`, `radio1`, etc.
### Country Code ⚠
The radio defaults to "00" for World domain, but some systems may ship with a
factory default country code (typically "DE" for the BPi-R3).
> [!IMPORTANT] Legal notice!
> The `country-code` setting is **legally required** and determines
> which WiFi channels and power levels are permitted in your
> location. Using an incorrect country code may violate local wireless
> regulations.
**Common country codes, see [ISO 3166-1 alpha-2][1] for the complete list**:
- Europe:
- DE: Germany
- SE: Sweden
- GB: UK
- FR: France
- ES: Spain
- Americas:
- US: United States
- CA: Canada
- BR: Brazil
- Asia-Pacific:
- JP: Japan
- AU: Australia
- CN: China
### Basic Radio Setup
Configure the radio with channel, power, and regulatory domain.
**For Station (client) mode:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit hardware component radio0 wifi-radio</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set country-code DE</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>leave</b>
</code></pre>
**For Access Point mode:**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit hardware component radio0 wifi-radio</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set country-code DE</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set band 5GHz</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set channel 36</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>leave</b>
</code></pre>
**Key radio parameters:**
- `country-code`: Two-letter [ISO 3166-1 alpha-2][1] code, determines allowed
channels and maximum power. Examples: US, DE, GB, SE, FR, JP.
**⚠ Must match your physical location for legal compliance! ⚠**
- `band`: 2.4GHz, 5GHz, or 6GHz (required for AP mode). Automatically enables
appropriate WiFi standards:
- 2.4GHz: 802.11n/ax
- 5GHz: 802.11n/ac/ax
- 6GHz: 802.11ax
- `channel`: Channel number (1-196) or "auto". When set to "auto", defaults to
channel 6 for 2.4GHz, channel 36 for 5GHz, or channel 109 for 6GHz
- `probe-timeout`: Seconds to wait for PHY detection at boot (default: 0). Set
to a non-zero value (e.g., 30) for USB WiFi dongles that are slow to
initialize due to firmware loading
> [!NOTE]
> TX power and channel width are automatically determined by the driver
> based on regulatory constraints, PHY mode, and hardware capabilities.
### WiFi 6 Support
WiFi 6 (802.11ax) is always enabled in AP mode on all bands, providing improved
performance through features like OFDMA, BSS Coloring, and beamforming.
**WiFi 6 Features (always enabled):**
- **OFDMA**: Better multi-user efficiency in dense environments
- **BSS Coloring**: Reduced interference from neighboring networks
- **Beamforming**: Improved signal quality and range
**Requirements:**
- Hardware must support 802.11ax
- Client devices must support WiFi 6 for full benefits
- Older WiFi 5/4 clients can still connect but won't use WiFi 6 features
## Discovering Available Networks
Before connecting to a WiFi network, you need to discover which networks
are available. Infix automatically scans for networks when a WiFi interface
is created with a radio reference.
### Enable Background Scanning
To enable scanning without connecting, configure the radio and create a WiFi
interface referencing it:
**Step 1: Configure the radio**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit hardware component radio0 wifi-radio</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set country-code DE</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>leave</b>
</code></pre>
**Step 2: Create WiFi interface with radio reference only**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface wifi0</b>
admin@example:/config/interface/wifi0/> <b>set wifi radio radio0</b>
admin@example:/config/interface/wifi0/> <b>leave</b>
</code></pre>
The system will now start scanning in the background. The interface will
operate in scan-only mode until you configure a specific mode (station or
access-point).
### View Available Networks
Use `show interface` to see discovered networks and their signal strength:
<pre class="cli"><code>admin@example:/> <b>show interface wifi0</b>
```
admin@infix-00-00-00:/> show interface wifi0
name : wifi0
type : wifi
index : 3
mtu : 1500
operational status : up
ip forwarding : enabled
operational status : down
physical address : f0:09:0d:36:5f:86
ipv4 addresses : 192.168.1.100/24 (dhcp)
ipv4 addresses :
ipv6 addresses :
in-octets : 148388
out-octets : 24555
mode : station
ssid : MyNetwork
signal : -45 dBm (good)
rx bitrate : 72.2 Mbps
tx bitrate : 86.6 Mbps
──────────────────────────────────────────────────────────────────────
<span class="title">Available Networks</span>
<span class="header">SSID BSSID SECURITY SIGNAL CHANNEL</span>
MyNetwork b4:fb:e4:17:b6:a7 WPA2-Personal good 6
GuestWiFi c8:3a:35:12:34:56 WPA2-Personal fair 11
CoffeeShop 00:1a:2b:3c:4d:5e Open bad 1
</code></pre>
SSID : ----
Signal : ----
In the CLI, signal strength is reported as: excellent, good, fair or bad.
For precise signal strength values in dBm, use NETCONF or RESTCONF to access
the `signal-strength` leaf in the operational datastore.
SSID ENCRYPTION SIGNAL
ssid1 WPA2-Personal excellent
ssid2 WPA2-Personal excellent
ssid3 WPA2-Personal excellent
ssid4 WPA2-Personal good
ssid5 WPA2-Personal good
ssid6 WPA2-Personal good
```
## Station Mode (Client)
In the CLI, signal strength is reported as: excellent, good, poor or
bad. For precise values, use NETCONF or RESTCONF, where the RSSI (in
dBm) is available in the operational datastore.
Station mode connects to an existing Wi-Fi network. Before configuring station
mode, follow the "Discovering Available Networks (Scanning)" section above to
scan for available networks and identify the SSID you want to connect to.
Configure your Wi-Fi secret in the keystore, it should be between 8
and 63 characters
### Step 1: Configure Password
```
admin@example:/> configure
admin@example:/config/> edit keystore symmetric-key example
admin@example:/config/keystore/…/example/> set key-format wifi-preshared-key-format
admin@example:/config/keystore/…/example/> set cleartext-key mysecret
admin@example:/config/keystore/…/example/> leave
admin@example:/>
```
Create a keystore entry for your WiFi password (8-63 characters):
Configure the Wi-Fi settings, set secret to the name selected above
for the symmetric key, in this case `example`.
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit keystore symmetric-key my-wifi-key</b>
admin@example:/config/keystore/…/my-wifi-key/> <b>set key-format wifi-preshared-key-format</b>
admin@example:/config/keystore/…/my-wifi-key/> <b>set symmetric-key MyPassword123</b>
admin@example:/config/keystore/…/my-wifi-key/> <b>leave</b>
</code></pre>
WPA2 or WPA3 encryption will be automatically selected based on what
the access point supports. No manual selection is required unless
connecting to an open network. No support for certificate based
authentication yet.
### Step 2: Connect to Network
Unencrypted network is also supported, to connect to an unencrypted
network (generally not recommended):
```
admin@example:/config/interface/wifi0/> set wifi encryption disabled
```
Configure station mode with the SSID and password to connect:
A valid `country-code` is also required for regulatory compliance, the
valid codes are documented in the YANG model `infix-wifi-country-codes`
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface wifi0</b>
admin@example:/config/interface/wifi0/> <b>set wifi station ssid MyHomeNetwork</b>
admin@example:/config/interface/wifi0/> <b>set wifi station security secret my-wifi-key</b>
admin@example:/config/interface/wifi0/> <b>leave</b>
</code></pre>
The connection attempt will start immediately. You can verify the connection status:
```
admin@example:/> configure
admin@example:/config/> edit interface wifi0
admin@example:/config/interface/wifi0/>
admin@example:/config/interface/wifi0/> set wifi ssid ssid1
admin@example:/config/interface/wifi0/> set wifi secret example
admin@example:/config/interface/wifi0/> set wifi country-code SE
admin@example:/config/interface/wifi0/> leave
```
<pre class="cli"><code>admin@example:/> <b>show interface wifi0</b>
name : wifi0
type : wifi
operational status : up
physical address : f0:09:0d:36:5f:86
SSID : MyHomeNetwork
Signal : excellent
</code></pre>
The Wi-Fi negotiation should now start immediately, provided that the
SSID and pre-shared key are correct. You can verify the connection by
running `show interface` again.
**Station configuration parameters:**
- `radio`: Reference to the WiFi radio (mandatory) - already set during scanning
- `station ssid`: Network name to connect to (mandatory)
- `station security mode`:
- `auto`: default, WPA2/WPA3 auto-negotiation
- `disabled`: open network
- `station security secret`: Reference to keystore entry, required unless mode
is `disabled`
```
admin@example:/> show interface
INTERFACE PROTOCOL STATE DATA
lo loopback UP
ipv4 127.0.0.1/8 (static)
ipv6 ::1/128 (static)
e1 ethernet UP 02:00:00:00:00:01
ipv6 fe80::ff:fe00:1/64 (link-layer)
ipv6 fec0::ff:fe00:1/64 (link-layer)
wifi0 ethernet UP f0:09:0d:36:5f:86
wifi ssid: ssid1, signal: excellent
> [!NOTE]
> The `auto` security mode automatically selects WPA3-SAE or WPA2-PSK based on
> what the access point supports, prioritizing WPA3 for better security.
> Certificate-based authentication (802.1X/EAP) is not yet supported.
admin@example:/>
```
## Access Point Mode
## Troubleshooting Connection Issues
Access Point (AP) mode allows your device to create a WiFi network that
other devices can connect to. APs are configured as virtual interfaces on
a WiFi radio.
Use `show wifi scan wifi0` and `show interface` to verify signal strength
and connection status. If issues arise, try the following
troubleshooting steps:
### Basic AP Configuration
1. **Verify signal strength**: Check that the target network shows "good" or "excellent" signal
2. **Check credentials**: Verify the preshared key in `ietf-keystore`
3. **Review logs**: Check system logs with `show log` for Wi-Fi related errors
4. **Regulatory compliance**: Ensure the country-code matches your location
5. **Hardware detection**: Confirm the adapter appears in `show interface`
First, ensure the radio is configured (see Radio Configuration above). Then
create a keystore entry for your WiFi password and configure the AP interface:
**Step 1: Create keystore entry for the WiFi password**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit keystore symmetric-key my-wifi-secret</b>
admin@example:/config/keystore/…/my-wifi-secret/> <b>set key-format wifi-preshared-key-format</b>
admin@example:/config/keystore/…/my-wifi-secret/> <b>set symmetric-key MySecurePassword123</b>
admin@example:/config/keystore/…/my-wifi-secret/> <b>end</b>
</code></pre>
**Step 2: Create the AP interface**
<pre class="cli"><code>admin@example:/config/> <b>edit interface wifi0</b>
admin@example:/config/interface/wifi0/> <b>set wifi radio radio0</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point ssid MyNetwork</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point security mode wpa2-personal</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point security secret my-wifi-secret</b>
admin@example:/config/interface/wifi0/> <b>leave</b>
</code></pre>
> [!NOTE]
> Using `wifiN` as the interface name automatically sets the type to WiFi.
> Alternatively, you can use any name and explicitly set `type wifi`.
**Access Point configuration parameters:**
- `radio`: Reference to the WiFi radio (mandatory)
- `access-point ssid`: Network name (SSID) to broadcast
- `access-point hidden`: Set to `true` to hide SSID (optional, default: false)
- `access-point security mode`: Security mode (see below)
- `access-point security secret`: Reference to keystore entry (for secured networks)
**Security modes:**
- `open`: No encryption (not recommended)
- `wpa2-personal`: WPA2-PSK (most compatible)
- `wpa3-personal`: WPA3-SAE (more secure, requires WPA3-capable clients)
- `wpa2-wpa3-personal`: Mixed mode (maximum compatibility)
### SSID Hiding
To create a hidden network that doesn't broadcast its SSID:
<pre class="cli"><code>admin@example:/config/interface/wifi0/> <b>set wifi access-point hidden true</b>
</code></pre>
### Multi-SSID Configuration
Multiple AP interfaces on the same radio allow broadcasting multiple SSIDs,
each with independent security settings. This is useful for guest networks,
IoT devices, or segregating traffic into different VLANs.
**Step 1: Configure the radio** (shared by all APs)
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit hardware component radio0 wifi-radio</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set country-code DE</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set band 5GHz</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>set channel 36</b>
admin@example:/config/hardware/component/radio0/wifi-radio/> <b>leave</b>
</code></pre>
**Step 2: Configure keystore secrets**
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit keystore symmetric-key main-secret</b>
admin@example:/config/keystore/…/main-secret/> <b>set key-format wifi-preshared-key-format</b>
admin@example:/config/keystore/…/main-secret/> <b>set symmetric-key MyMainPassword</b>
admin@example:/config/> <b>edit keystore symmetric-key guest-secret</b>
admin@example:/config/keystore/…/guest-secret/> <b>set key-format wifi-preshared-key-format</b>
admin@example:/config/keystore/…/guest-secret/> <b>set symmetric-key GuestPassword123</b>
admin@example:/config/> <b>edit keystore symmetric-key iot-secret</b>
admin@example:/config/keystore/…/iot-secret/> <b>set key-format wifi-preshared-key-format</b>
admin@example:/config/keystore/…/iot-secret/> <b>set symmetric-key IoTDevices2025</b>
admin@example:/config/keystore/…/iot-secret/> <b>leave</b>
</code></pre>
**Step 3: Create multiple AP interfaces** (all on radio0)
<pre class="cli"><code>admin@example:/> <b>configure</b>
# Primary AP - Main network (WPA3 for maximum security)
admin@example:/config/> <b>edit interface wifi0</b>
admin@example:/config/interface/wifi0/> <b>set wifi radio radio0</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point ssid MainNetwork</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point security mode wpa3-personal</b>
admin@example:/config/interface/wifi0/> <b>set wifi access-point security secret main-secret</b>
# Guest AP - Guest network (WPA2/WPA3 mixed for compatibility)
admin@example:/config/> <b>edit interface wifi1</b>
admin@example:/config/interface/wifi1/> <b>set wifi radio radio0</b>
admin@example:/config/interface/wifi1/> <b>set wifi access-point ssid GuestNetwork</b>
admin@example:/config/interface/wifi1/> <b>set wifi access-point security mode wpa2-wpa3-personal</b>
admin@example:/config/interface/wifi1/> <b>set wifi access-point security secret guest-secret</b>
admin@example:/config/interface/wifi1/> <b>set custom-phys-address static 00:0c:43:26:60:01</b>
# IoT AP - IoT devices (WPA2 for older device compatibility)
admin@example:/config/> <b>edit interface wifi2</b>
admin@example:/config/interface/wifi2/> <b>set wifi radio radio0</b>
admin@example:/config/interface/wifi2/> <b>set wifi access-point ssid IoT-Devices</b>
admin@example:/config/interface/wifi2/> <b>set wifi access-point security mode wpa2-personal</b>
admin@example:/config/interface/wifi2/> <b>set wifi access-point security secret iot-secret</b>
admin@example:/config/interface/wifi2/> <b>set custom-phys-address static 00:0c:43:26:60:02</b>
admin@example:/config/interface/wifi2/> <b>leave</b>
</code></pre>
> [!IMPORTANT]
> **MAC Address Requirement for Multi-SSID:**
> When creating multiple AP interfaces on the same radio, you **must** configure
> a unique MAC address for each secondary interface (wifi1, wifi2, etc.) using
> `set custom-phys-address static <MAC>`. All interfaces on the same radio inherit
> the radio's hardware MAC address by default, which causes network conflicts. Only
> the primary interface (alphabetically first, e.g., wifi0) should use the default
> hardware MAC address.
>
> Choose MAC addresses from the same locally-administered range:
> - Primary (wifi0): Uses hardware MAC (e.g., `00:0c:43:26:60:00`)
> - Secondary (wifi1): `00:0c:43:26:60:01` (increment last octet)
> - Tertiary (wifi2): `00:0c:43:26:60:02` (increment last octet)
**Result:** Three SSIDs broadcasting simultaneously on radio0:
- `MainNetwork` (WPA3, most secure)
- `GuestNetwork` (WPA2/WPA3 mixed mode)
- `IoT-Devices` (WPA2 for compatibility)
All APs on the same radio share the same channel and physical layer settings
(configured at the radio level). Each AP can have its own:
- SSID (network name)
- Security mode and passphrase
- Hidden/visible SSID setting
- Bridge membership
You can verify the configuration with `show hardware component radio0` to see
radio settings, and `show interface` to see all active AP interfaces.
> [!IMPORTANT]
> AP and Station modes cannot be mixed on the same radio. All virtual interfaces
> on a radio must be the same mode (all APs or all Stations).
### AP as Bridge Port
WiFi AP interfaces can be added to bridges to integrate wireless devices
into your LAN:
<pre class="cli"><code>admin@example:/> <b>configure</b>
admin@example:/config/> <b>edit interface br0</b>
admin@example:/config/interface/br0/> <b>set type bridge</b>
admin@example:/config/> <b>edit interface wifi0</b>
admin@example:/config/interface/wifi0/> <b>set bridge-port bridge br0</b>
admin@example:/config/interface/wifi0/> <b>leave</b>
</code></pre>
## Troubleshooting
Use `show interface wifi0` to verify signal strength and connection status.
If issues arise, try the following troubleshooting steps:
1. **Verify signal strength**: Check that the target network shows
"good" or "excellent" signal in scan results
2. **Check credentials**: Verify the preshared key in the keystore
matches the network password
3. **Review logs**: Check system logs with `show log` for Wi-Fi related
errors
4. **Regulatory compliance**: Ensure the country-code on the radio
matches your location
5. **Hardware detection**: Confirm the WiFi radio appears in `show
hardware`
If issues persist, check the system log for specific error messages that
can help identify the root cause.
[1]: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
If issues persist, check the system log for specific error messages that can help identify the root cause.
+4 -14
View File
@@ -28,29 +28,18 @@ nav:
- Upgrading: cli/upgrade.md
- Docker Containers: container.md
- Networking:
- Overview: networking.md
- Common Settings: iface.md
- Bridging: bridging.md
- Link Aggregation: lag.md
- Ethernet Interfaces: ethernet.md
- IP Addressing: ip.md
- Routing: routing.md
- Network Configuration: networking.md
- Firewall Configuration: firewall.md
- Quality of Service: qos.md
- RMON Counters: eth-counters.md
- Tunneling (L2/L3): tunnels.md
- VPN Tunnels:
- Overview: vpn.md
- WireGuard: vpn-wireguard.md
- Wireless LAN (WiFi): wifi.md
- Services:
- Device Discovery: discovery.md
- DHCP Server: dhcp.md
- NTP Server: ntp.md
- System:
- Boot Procedure: boot.md
- Configuration: system.md
- Access Control (NACM): nacm.md
- Hardware Info & Status: hardware.md
- Management: management.md
- Syslog Support: syslog.md
@@ -59,15 +48,16 @@ nav:
- Scripting:
- Introduction: scripting.md
- Legacy Scripting: scripting-sysrepocfg.md
- NETCONF Scripting: scripting-netconf.md
- RESTCONF Scripting: scripting-restconf.md
- Production Testing: scripting-prod.md
- With NETCONF: scripting-netconf.md
- With RESTCONF: scripting-restconf.md
- Developer's Corner:
- Branding & Releases: branding.md
- Developer's Guide: developers-guide.md
- Developing with Buildroot: override-package.md
- Netboot HowTo: netboot.md
- Regression Testing: testing.md
- System Tuning Guide: system-tuning.md
- Test System Architecture: test-arch.md
- Virtual Environments: virtual.md
- Vital Product Data (VPD): vpd.md
+1
View File
@@ -34,6 +34,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/python-libyang/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"
-4
View File
@@ -5,8 +5,4 @@ config BR2_PACKAGE_BIN
help
Misc. tools for CLI and shell users.
Includes show (show.py) copy (NACM-aware datastore operations),
rpc (YANG RPC execution with NACM enforcement), erase, and files
commands.
https://github.com/kernelkit/infix
+1 -30
View File
@@ -10,9 +10,7 @@ BIN_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/bin
BIN_LICENSE = BSD-3-Clause
BIN_LICENSE_FILES = LICENSE
BIN_REDISTRIBUTE = NO
BIN_DEPENDENCIES = sysrepo libite \
host-python3 python3 host-python-pypa-build host-python-installer \
host-python-poetry-core
BIN_DEPENDENCIES = sysrepo libite
BIN_CONF_OPTS = --disable-silent-rules
BIN_AUTORECONF = YES
@@ -20,31 +18,4 @@ define BIN_CONF_ENV
CFLAGS="$(INFIX_CFLAGS)"
endef
define BIN_PERMISSIONS
/usr/bin/copy d 04750 root klish - - - - -
endef
define BIN_BUILD_PYTHON
cd $(BIN_SITE) && \
$(PKG_PYTHON_PEP517_ENV) $(HOST_DIR)/bin/python3 $(PKG_PYTHON_PEP517_BUILD_CMD) -o $(@D)/dist
mkdir -p $(TARGET_DIR)/usr/bin
rm -f $(TARGET_DIR)/usr/bin/show
cd $(@D) && \
$(HOST_DIR)/bin/python3 $(TOPDIR)/support/scripts/pyinstaller.py \
dist/*.whl \
--interpreter=/usr/bin/python3 \
--script-kind=posix \
--purelib=$(TARGET_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages \
--headers=$(TARGET_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
--scripts=$(TARGET_DIR)/usr/bin \
--data=$(TARGET_DIR)
endef
BIN_POST_INSTALL_TARGET_HOOKS += BIN_BUILD_PYTHON
define BIN_INSTALL_BASH_COMPLETION
install -D $(@D)/bash_completion.d/show \
$(TARGET_DIR)/etc/bash_completion.d/show
endef
BIN_POST_INSTALL_TARGET_HOOKS += BIN_INSTALL_BASH_COMPLETION
$(eval $(autotools-package))

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