Compare commits

...
12 Commits
Author SHA1 Message Date
Joachim WibergandGitHub f6f6381eaf Merge pull request #1433 from kernelkit/cand/v26.02.x
v26.02.1 Release Candidate
2026-03-11 14:07:13 +01:00
Joachim Wiberg e5754b4001 doc: prepare for v26.02.1 release
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-11 12:36:17 +01:00
Joachim Wiberg 6838cc9c25 confd: follow-up to OSPF point-to-multipoint
Add a must expression to ensure users do not set static neighbors when
the interface type is not point-to-multipoint or non-broadcast.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-11 12:36:17 +01:00
Mattias WalströmandJoachim Wiberg d869f6c478 Followup OSPF point-to-multipoint
[skip ci]
2026-03-11 12:36:16 +01:00
Mattias WalströmandJoachim Wiberg f37d29aa21 ospf: add point-to-multipoint and hybrid interface type support
Signed-off-by: Mattias Walström <lazzer@gmail.com>
2026-03-11 12:36:16 +01:00
ael-botandJoachim Wiberg 982a754472 Upgrade Linux kernel to 6.18.16 2026-03-10 14:33:33 +01:00
Joachim Wiberg 931ae71019 board: relocate SafeXcel firmware selection to Marvell BSPs
The MVEBU SafeXcel Crypto Engine firmware (linux-firmware minifw) was
originally added in 70c12c3 to the generic aarch64 defconfigs to silence
kernel probe failures on Marvell Armada SoCs (37xx, 7k, 8k, CN913x):

  crypto-safexcel f2800000.crypto: Firmware load failed.
  crypto-safexcel f2800000.crypto: HW init failed (-2)

It was then accidentally dropped in 0e2d12e (kernel upgrade to 6.18),
which rebased on a tree that predated the firmware addition.

Rather than restoring it to the generic defconfigs, move it to the two
Marvell board Config.in files where it actually belongs — consistent
with how RTL8169 firmware was handled for the Raspberry Pi CM4 IoT
Router Board Mini in 68313773.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-10 14:27:31 +01:00
Joachim Wiberg c69a617ecb patches: lift iptables name length limit in firewalld
A legacy name length limit in firewalld triggered problems with longer
policy names.  This patch to firewalld lifts that limit by checking the
backend in use, no limit for nftables.

Fixes #1389

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-10 14:27:31 +01:00
Joachim Wiberg c79beea4ec statd: silence 'show firewall' when firewall is disabled
Fixes #1416

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-10 14:27:30 +01:00
Joachim Wiberg cf1e81c8d1 package/skeleton-init-fint: increase zebra netlink buffer
Increase Zebra NETLINK buffer to fix reported issues with zebra being
out of sync with kernel routes and interface changes.

Also, try '-a' option to allow other processes to delete zebra routes.

Other changes in this commit:
 - Minor fixes to Finit service files for consistency
 - Empty daemon.conf stub files to silence bogus mgmtd errors at startup
 - Relocate all skeleton files from board/common to separate from files
   that are actual Infix additions and what's package system integration

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-03-10 14:27:30 +01:00
Mattias WalströmandJoachim Wiberg e04937a0f7 GPS: Disable GPS in _minimal config 2026-03-10 14:27:30 +01:00
Mattias WalströmandJoachim Wiberg e838f6dfd8 yang: add feature flags for wifi and gps in infix-hardware 2026-03-10 14:27:27 +01:00
86 changed files with 1473 additions and 129 deletions
+1
View File
@@ -1,5 +1,6 @@
config BR2_PACKAGE_ALDER_ALDER
bool "Alder"
depends on BR2_aarch64
select BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW
help
Alder
@@ -1,5 +1,6 @@
config BR2_PACKAGE_MARVELL_CN9130_CRB
bool "Marvell CN9130-CRB"
depends on BR2_aarch64
select BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW
help
Customer Reference Board for CN9130
@@ -1,5 +1,6 @@
config BR2_PACKAGE_MARVELL_ESPRESSOBIN
bool "Marvell ESPRESSObin"
depends on BR2_aarch64
select BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW
help
Marvell ESPRESSObin
+1
View File
@@ -1,5 +1,6 @@
config BR2_PACKAGE_STYX_DCP_SC_28P
bool "Styx DCP-SC-28P"
depends on BR2_aarch64
select BR2_PACKAGE_LINUX_FIRMWARE_INSIDE_SECURE_MINIFW
help
Styx DCP-SC-28P
+1 -4
View File
@@ -27,7 +27,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
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
@@ -41,9 +41,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_MDIO_TOOLS=y
+1 -5
View File
@@ -27,7 +27,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
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
@@ -41,9 +41,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_MDIO_TOOLS=y
@@ -126,7 +123,6 @@ INFIX_DESC="Infix is an immutable, friendly, and secure operating system that tu
INFIX_HOME="https://github.com/kernelkit/infix/"
INFIX_DOC="https://www.kernelkit.org/infix/"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_FEATURE_GPS=y
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_NETD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
+1 -4
View File
@@ -28,7 +28,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/arm/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -43,9 +43,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_MDIO_TOOLS=y
+1 -5
View File
@@ -28,7 +28,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL_INFIX_PATH}/board/arm/linux_defconfig"
BR2_LINUX_KERNEL_INSTALL_TARGET=y
@@ -43,9 +43,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_MDIO_TOOLS=y
@@ -126,7 +123,6 @@ INFIX_DESC="Infix is an immutable, friendly, and secure operating system that tu
INFIX_HOME="https://github.com/kernelkit/infix/"
INFIX_DOC="https://www.kernelkit.org/infix/"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_FEATURE_GPS=y
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_NETD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
-3
View File
@@ -52,9 +52,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_MDIO_TOOLS=y
+1 -4
View File
@@ -26,7 +26,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
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
@@ -41,9 +41,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_RNG_TOOLS=y
+1 -5
View File
@@ -26,7 +26,7 @@ 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.15"
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.18.16"
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
@@ -41,9 +41,6 @@ BR2_PACKAGE_DBUS_CXX=y
BR2_PACKAGE_DBUS_GLIB=y
BR2_PACKAGE_EUDEV_RULES_GEN=y
# BR2_PACKAGE_EUDEV_ENABLE_HWDB is not set
BR2_PACKAGE_GPSD_DEVICES="/dev/gps0"
BR2_PACKAGE_GPSD_MAX_CLIENT_VALUE=2
BR2_PACKAGE_GPSD_MAX_DEV_VALUE=1
BR2_PACKAGE_GPTFDISK=y
BR2_PACKAGE_GPTFDISK_SGDISK=y
BR2_PACKAGE_RNG_TOOLS=y
@@ -125,7 +122,6 @@ INFIX_DESC="Infix is an immutable, friendly, and secure operating system that tu
INFIX_HOME="https://github.com/kernelkit/infix/"
INFIX_DOC="https://www.kernelkit.org/infix/"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_FEATURE_GPS=y
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_NETD=y
BR2_PACKAGE_CONFD_TEST_MODE=y
+19
View File
@@ -3,6 +3,24 @@ Change Log
All notable changes to the project are documented in this file.
[v26.02.1][] - 2026-03-11
-------------------------
### Changes
- Upgrade Linux kernel to 6.18.16 (LTS)
- Add support for disabling WiFi and GPS features in builds
- Add OSPF point-to-multipoint (P2MP) and hybrid interface type support. This
also includes support for setting static neighbors, issue #1426
### Fixes
- Fix #1389: legacy name limit in firewalld triggered problems with policy names
- Fix #1416: `show firewall` command show an error when the firewall is disabled
- Fix instabilities in Zebra route manager after Frr upgrade in v26.02.0
- Fix regression in MVEBU SafeXcel Crypto Engine for Marvell Armada SOCs (37xx,
7k, 8k, and CN913x series). Firmware package lost in v26.01.0
[v26.02.0][] - 2026-03-01
-------------------------
@@ -1932,6 +1950,7 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
[buildroot]: https://buildroot.org/
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v26.02.0...HEAD
[v26.02.1]: https://github.com/kernelkit/infix/compare/v26.02.0...v26.02.1
[v26.02.0]: https://github.com/kernelkit/infix/compare/v26.01.0...v26.02.0
[v26.01.0]: https://github.com/kernelkit/infix/compare/v25.11.0...v26.01.0
[v25.11.0]: https://github.com/kernelkit/infix/compare/v25.10.0...v25.11.0
+60
View File
@@ -131,6 +131,66 @@ an Ethernet interface can be done as follows.
admin@example:/config/routing/…/ospf/area/0.0.0.0/interface/e0/>
</code></pre>
### Point-to-Multipoint
Point-to-Multipoint (P2MP) is used when multiple OSPF routers share a
common network segment but should form individual adjacencies rather
than electing a Designated Router (DR). This is common in NBMA-like
environments, DMVPN, or hub-and-spoke topologies.
Infix supports two P2MP variants via the `interface-type` setting:
| **Interface Type** | **Behavior** |
|:----------------------|:-----------------------------------------------|
| `hybrid` | P2MP with multicast Hellos (broadcast-capable) |
| `point-to-multipoint` | P2MP with unicast Hellos (non-broadcast) |
#### Hybrid (broadcast-capable P2MP)
Use `hybrid` when all neighbors on the segment can receive multicast.
Hello packets are sent to the standard OSPF multicast address (224.0.0.5)
and neighbors are discovered automatically — no manual neighbor
configuration is needed.
<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 interface-type hybrid</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
#### Non-broadcast P2MP
Use `point-to-multipoint` when the network does not support multicast.
Hello packets are sent as unicast directly to each configured neighbor.
Since neighbors cannot be discovered automatically, they must be
configured explicitly using static neighbors (see below).
<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 interface-type point-to-multipoint</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
### Static Neighbors
When using non-broadcast interface types (such as `point-to-multipoint`),
OSPF cannot discover neighbors via multicast. Static neighbors must be
configured so the router knows where to send unicast Hello packets.
<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 static-neighbors neighbor 10.0.123.2</b>
admin@example:/config/routing/…/ospf/> <b>set area 0.0.0.0 interface e0 static-neighbors neighbor 10.0.123.3</b>
admin@example:/config/routing/…/ospf/> <b>leave</b>
admin@example:/>
</code></pre>
> [!NOTE]
> Static neighbors are only needed for non-broadcast interface types.
> With `hybrid` (or `broadcast`), neighbors are discovered automatically
> via multicast.
### OSPF global settings
In addition to *area* and *interface* specific settings, OSPF provides
+12
View File
@@ -30,6 +30,11 @@ CONFD_CONF_OPTS += --enable-wifi
else
CONFD_CONF_OPTS += --disable-wifi
endif
ifeq ($(BR2_PACKAGE_FEATURE_GPS),y)
CONFD_CONF_OPTS += --enable-gps
else
CONFD_CONF_OPTS += --disable-gps
endif
define CONFD_INSTALL_EXTRA
for fn in confd.conf resolvconf.conf; do \
cp $(CONFD_PKGDIR)/$$fn $(FINIT_D)/available/; \
@@ -80,6 +85,12 @@ define CONFD_INSTALL_YANG_MODULES_WIFI
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/wifi.inc
endef
endif
ifeq ($(BR2_PACKAGE_FEATURE_GPS),y)
define CONFD_INSTALL_YANG_MODULES_GPS
$(COMMON_SYSREPO_ENV) \
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/gps.inc
endef
endif
# PER_PACKAGE_DIR
# Since the last package in the dependency chain that runs sysrepoctl is confd, we need to
@@ -109,6 +120,7 @@ CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_EXTRA
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_CONTAINERS
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_WIFI
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_GPS
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_IN_ROMFS
CONFD_TARGET_FINALIZE_HOOKS += CONFD_CLEANUP
@@ -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 -a -s 90000000 -u frr -g frr --log syslog --log-level err"
@@ -1,2 +1,3 @@
service <!> pid:!/run/frr/mgmtd.pid env:-/etc/default/mgmtd \
[2345] mgmtd $MGMTD_ARGS -- FRR MGMT daemon
[2345] mgmtd $MGMTD_ARGS \
-- FRR MGMT daemon
@@ -1,2 +1,3 @@
service <!pid/zebra> env:-/etc/default/ospfd \
[2345] ospfd $OSPFD_ARGS -- OSPF daemon
service <!pid/zebra> pid:!/run/frr/ospfd.pid env:-/etc/default/ospfd \
[2345] ospfd $OSPFD_ARGS \
-- OSPF daemon
@@ -1,3 +1,3 @@
service <pid/zebra> env:-/etc/default/ripd \
[2345] ripd $RIPD_ARGS
service <pid/zebra> pid:!/run/frr/ripd.pid env:-/etc/default/ripd \
[2345] ripd $RIPD_ARGS \
-- RIP daemon
@@ -1,3 +1,3 @@
service <!pid/mgmtd> pid:!/run/frr/zebra.pid env:-/etc/default/zebra \
[2345] zebra $ZEBRA_ARGS
service <!pid/mgmtd> pid:!/run/frr/zebra.pid env:-/etc/default/zebra \
[2345] zebra $ZEBRA_ARGS \
-- Zebra routing daemon
@@ -1,5 +1,4 @@
# Default FRR daemons file for Infix - confd overwrites on routing changes.
# watchfrr, zebra, mgmtd, and staticd are always started by frrinit.sh.
# Default FRR daemons file used with watchfrr, started by frrinit.sh.
ospfd=no
ripd=no
bfdd=no
@@ -25,4 +24,3 @@ staticd_options="-A 127.0.0.1"
bfdd_options=" -A 127.0.0.1"
frr_profile="traditional"
@@ -0,0 +1 @@
! Empty stub — mgmtd reads its own config at startup; file must exist to avoid log noise.
@@ -0,0 +1 @@
! Empty stub — mgmtd reads per-daemon configs at startup; file must exist to avoid log noise.
@@ -0,0 +1 @@
! Empty stub — mgmtd reads per-daemon configs at startup; file must exist to avoid log noise.
@@ -0,0 +1 @@
! Empty stub — mgmtd reads per-daemon configs at startup; file must exist to avoid log noise.
@@ -0,0 +1 @@
! Empty stub — mgmtd reads per-daemon configs at startup; file must exist to avoid log noise.
@@ -1,7 +1,7 @@
From 03f273fc540082d1eaa23bd9b5847e695afd8283 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Thu, 25 Sep 2025 15:00:54 +0200
Subject: [PATCH] Silence warnings about old backends
Subject: [PATCH 1/2] Silence warnings about old backends
Organization: Wires
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
@@ -0,0 +1,95 @@
From 6ab218fe7f2c7027cc5347e3b082285870c502e6 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Fri, 6 Mar 2026 07:44:38 +0100
Subject: [PATCH 2/2] fix(functions): lift iptables name length limit when
using nftables
Organization: Wires
The max_zone_name_len() and max_policy_name_len() functions return 17
and 18 respectively, derived from iptables' 28-char netfilter chain name
limit. These limits are applied unconditionally in Zone.check_name()
and Policy.check_name() regardless of the active backend.
When FirewallBackend=nftables nftables imposes no such restriction, so
user-defined zone and policy names (e.g. "appletv-to-lan-guest", 20
chars) that exceed the iptables-derived limit are incorrectly rejected.
Add _nftables_backend() which reads firewalld.conf directly so the check
can be skipped without threading backend context through to check_name()
call sites, which have no access to all_io_objects. When nftables is
active, both functions return sys.maxsize, effectively disabling the
length check.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
---
src/firewall/functions.py | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/src/firewall/functions.py b/src/firewall/functions.py
index 27c862fd..1b8a32ce 100644
--- a/src/firewall/functions.py
+++ b/src/firewall/functions.py
@@ -10,9 +10,10 @@ import os
import os.path
import shlex
import string
+import sys
import tempfile
from firewall.core.logger import log
-from firewall.config import FIREWALLD_TEMPDIR, FIREWALLD_PIDFILE
+from firewall.config import FIREWALLD_CONF, FIREWALLD_TEMPDIR, FIREWALLD_PIDFILE
NOPRINT_TRANS_TABLE = {
# Limit to C0 and C1 code points. Building entries for all unicode code
@@ -576,12 +577,35 @@ def ppid_of_pid(pid):
return pid
+def _nftables_backend():
+ """Return True if FirewallBackend=nftables is configured in firewalld.conf.
+
+ When using nftables the iptables-derived 28-char chain name limit does not
+ apply. Reading the config file directly avoids threading backend context
+ through check_name() call sites, which have no access to all_io_objects.
+ """
+ try:
+ with open(FIREWALLD_CONF) as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("FirewallBackend="):
+ return line.split("=", 1)[1].strip() == "nftables"
+ except OSError:
+ pass
+ return False
+
+
def max_policy_name_len():
"""
iptables limits length of chain to (currently) 28 chars.
The longest chain we create is POST_<policy>_allow,
which leaves 28 - 11 = 17 chars for <policy>.
+
+ When using the nftables backend, nftables imposes no practical name length
+ restriction, so we return sys.maxsize to lift the check entirely.
"""
+ if _nftables_backend():
+ return sys.maxsize
from firewall.core.ipXtables import POLICY_CHAIN_PREFIX
from firewall.core.base import SHORTCUTS
@@ -594,7 +618,12 @@ def max_zone_name_len():
Netfilter limits length of chain to (currently) 28 chars.
The longest chain we create is POST_<zone>_allow,
which leaves 28 - 11 = 17 chars for <zone>.
+
+ When using the nftables backend, nftables imposes no practical name length
+ restriction, so we return sys.maxsize to lift the check entirely.
"""
+ if _nftables_backend():
+ return sys.maxsize
from firewall.core.base import SHORTCUTS
longest_shortcut = max(map(len, SHORTCUTS.values()))
--
2.43.0
@@ -1,4 +1,4 @@
From 443245154df3a713a61feffa5043da4c200b30fa Mon Sep 17 00:00:00 2001
From 2ca55761d22dbc39d26862cf94577cf44f4b85a0 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 19 Sep 2023 18:38:10 +0200
Subject: [PATCH 01/33] net: phy: marvell10g: Support firmware loading on
@@ -1,4 +1,4 @@
From a81a31111af41ce03bfd0a6bf493a440195c0aa8 Mon Sep 17 00:00:00 2001
From 554729f2a8c83f617663c097cc389b5c791db8aa Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 21 Nov 2023 20:15:24 +0100
Subject: [PATCH 02/33] net: phy: marvell10g: Fix power-up when strapped to
@@ -1,4 +1,4 @@
From 05bbe3556f357ba52eb12aef54831c2a7270f4fe Mon Sep 17 00:00:00 2001
From 7090bf6cbf332d9a38e04a58b026d2d00701ca67 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 15 Nov 2023 20:58:42 +0100
Subject: [PATCH 03/33] net: phy: marvell10g: Add LED support for 88X3310
@@ -1,4 +1,4 @@
From e4d030d502f358a4ed21eb75e2c3cffbe5c2b8da Mon Sep 17 00:00:00 2001
From 7776e8acf62062136892b9623c24898c09778e48 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 12 Dec 2023 09:51:05 +0100
Subject: [PATCH 04/33] net: phy: marvell10g: Support LEDs tied to a single
@@ -1,4 +1,4 @@
From 44c1b964008099707a86150597f07fb9afa2d4ab Mon Sep 17 00:00:00 2001
From 96ce164208881c981e9e8b1231e2b45957a89b5e Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 27 Mar 2024 10:10:19 +0100
Subject: [PATCH 05/33] net: phy: Do not resume PHY when attaching
@@ -1,4 +1,4 @@
From a0ed79ec338c0a1ec647ecffe5de532bc93ae34e Mon Sep 17 00:00:00 2001
From 74ce9cb9a4845537644a67769ee9f441bf9d3a78 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Mon, 4 Mar 2024 16:47:28 +0100
Subject: [PATCH 06/33] net: bridge: avoid classifying unknown multicast as
@@ -1,4 +1,4 @@
From 1d7a80c8f0a1f1fdb9feededbe6a81ef95ea235f Mon Sep 17 00:00:00 2001
From e7b3717762434f780616a0b641169f5cfa1a2398 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Tue, 5 Mar 2024 06:44:41 +0100
Subject: [PATCH 07/33] net: bridge: Ignore router ports when forwarding L2
@@ -1,4 +1,4 @@
From 7d5b408393f724aa3fb9109d0373270bff5912a4 Mon Sep 17 00:00:00 2001
From fabc6f846e244fd2b67d26155d644238505b949b Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Thu, 4 Apr 2024 16:36:30 +0200
Subject: [PATCH 08/33] net: bridge: drop delay for applying strict multicast
@@ -1,4 +1,4 @@
From fcb5ec6195e9201d547148f23115305d012258e1 Mon Sep 17 00:00:00 2001
From 4ee3858a7d7f02746187d8bbc6011038747cab35 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 16 May 2024 14:51:54 +0200
Subject: [PATCH 09/33] net: bridge: Differentiate MDB additions from
@@ -1,4 +1,4 @@
From ea7944d9e73280180e6e80e7de5e1a20e308ecab Mon Sep 17 00:00:00 2001
From 319ed7a2257bd18b5b0d23c9f24af9fd127b7667 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Fri, 24 Nov 2023 23:29:55 +0100
Subject: [PATCH 10/33] nvmem: layouts: onie-tlv: Let device probe even when
@@ -1,4 +1,4 @@
From 6d8bdf087b6b5f4a1a714858fcf9c548afee0041 Mon Sep 17 00:00:00 2001
From 0ee33120c15d36ea49121936acb0b9cb860e0f5f Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Sun, 11 Aug 2024 11:27:35 +0200
Subject: [PATCH 11/33] net: usb: r8152: add r8153b support for link/activity
@@ -18,7 +18,7 @@ Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
1 file changed, 8 insertions(+)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 6a43054d5171..ef8bcb4a7339 100644
index da8de7b1a489..36d79a77316c 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -41,6 +41,11 @@
@@ -33,7 +33,7 @@ index 6a43054d5171..ef8bcb4a7339 100644
#define R8152_PHY_ID 32
#define PLA_IDR 0xc000
@@ -7277,6 +7282,9 @@ static void r8153b_init(struct r8152 *tp)
@@ -7279,6 +7284,9 @@ static void r8153b_init(struct r8152 *tp)
ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
@@ -1,4 +1,4 @@
From e6250ce25bc96c91c74ad8bdea6132087bc3c8d3 Mon Sep 17 00:00:00 2001
From cf134950928be5c5955cc70c69e273a316bac69f Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Sun, 10 Aug 2025 18:52:54 +0200
Subject: [PATCH 12/33] arm64: dts: mediatek: mt7986a: rename BPi R3 ports to
@@ -1,4 +1,4 @@
From dcafe00d03f102ce48cb9068c884009e753b53bf Mon Sep 17 00:00:00 2001
From 799998c00feee44d4c74556022904ba7a0bdfac8 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Wed, 20 Aug 2025 21:38:24 +0200
Subject: [PATCH 13/33] drm/panel-simple: Add a timing for the Raspberry Pi 7"
@@ -1,4 +1,4 @@
From 38d942ffce63ee1fa9beecf6bac3d7b30e87c87a Mon Sep 17 00:00:00 2001
From f01bf9ba38f75e3ef290cdd2a22df025768dd8b8 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Thu, 21 Aug 2025 11:20:23 +0200
Subject: [PATCH 14/33] input:touchscreen:edt-ft5x06: Add polled mode
@@ -1,4 +1,4 @@
From 60cd0f84c208ab9bc53ad070e81bb0173e356889 Mon Sep 17 00:00:00 2001
From dd7bb94f604192615f1f73a362fb0e2471ff8e1b Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 12 Mar 2024 10:27:24 +0100
Subject: [PATCH 15/33] [FIX] net: dsa: mv88e6xxx: Fix timeout on waiting for
@@ -1,4 +1,4 @@
From de9af4997489a4f2a4110412b418bb7a317664fe Mon Sep 17 00:00:00 2001
From 5dbb37d98861fab5cdf35947406133b494850d07 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 27 Mar 2024 15:52:43 +0100
Subject: [PATCH 16/33] net: dsa: mv88e6xxx: Improve indirect register access
@@ -1,4 +1,4 @@
From 94db20c708ac578007ef56ebd6a4321f45ca2ba7 Mon Sep 17 00:00:00 2001
From ef510ee5006cb4d34bbf53edc2c5d82cee557a56 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Mon, 22 Apr 2024 23:18:01 +0200
Subject: [PATCH 17/33] net: dsa: mv88e6xxx: Honor ports being managed via
@@ -1,4 +1,4 @@
From a52c2c0be135f32dac53410a6f67226ecb59da58 Mon Sep 17 00:00:00 2001
From cb18e0e47ef6696d7e2949af53c6f224ff112160 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 24 Apr 2024 22:41:04 +0200
Subject: [PATCH 18/33] net: dsa: mv88e6xxx: Limit rsvd2cpu policy to user
@@ -1,4 +1,4 @@
From 668ba9f49cd17cb27145fbe579931b9ddf74ea88 Mon Sep 17 00:00:00 2001
From 68e1ad6de79b30163ee9c610174e704db44f9c29 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 28 May 2024 10:38:42 +0200
Subject: [PATCH 19/33] net: dsa: tag_dsa: Use tag priority as initial
@@ -1,4 +1,4 @@
From 79450dc7dd78cb3d1e3798180151e4927f3d862f Mon Sep 17 00:00:00 2001
From 973d7b6c0928d41ed86702c4b7e9d140c7acb443 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 16 Jan 2024 16:00:55 +0100
Subject: [PATCH 20/33] net: dsa: Support MDB memberships whose L2 addresses
@@ -1,4 +1,4 @@
From 7d282dfc8044ad74aa190203efdc350bf9ab8c97 Mon Sep 17 00:00:00 2001
From f23311c2898a40e0f330c3d21907d2d14ab66b85 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Thu, 21 Mar 2024 19:12:15 +0100
Subject: [PATCH 21/33] net: dsa: Support EtherType based priority overrides
@@ -1,4 +1,4 @@
From 2b0679aa4727f71f3858291002c3abb5eade7ca7 Mon Sep 17 00:00:00 2001
From 02a6215df9d126dbe0079eab7b4b95a49be072fe Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Fri, 22 Mar 2024 16:15:43 +0100
Subject: [PATCH 22/33] net: dsa: mv88e6xxx: Support EtherType based priority
@@ -1,4 +1,4 @@
From 7f6fd96a6b80c541b0fba0e5cc9de10aa0801eb0 Mon Sep 17 00:00:00 2001
From 8de2cab0aef8e63e6f95d49ccf50aac05e3834d1 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 28 May 2024 11:04:22 +0200
Subject: [PATCH 23/33] net: dsa: mv88e6xxx: Add mqprio qdisc support
@@ -1,4 +1,4 @@
From 54a42d398869bf484d31a499af28ba95ce75c412 Mon Sep 17 00:00:00 2001
From 0de73e629b8fabb852a239a67e91954d15326c1b Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 29 May 2024 13:20:41 +0200
Subject: [PATCH 24/33] net: dsa: mv88e6xxx: Use VLAN prio over IP when both
@@ -1,4 +1,4 @@
From dbc7e27badea74027b2742fe768db95e48edc4d7 Mon Sep 17 00:00:00 2001
From 3caaed0cca0c4ca5719b0434a30aa8dec77ef717 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Tue, 26 Nov 2024 19:45:59 +0100
Subject: [PATCH 25/33] [FIX] net: dsa: mv88e6xxx: Trap locally terminated
@@ -1,4 +1,4 @@
From 6ffe3f8912a00fd32f5607c9aa25b7ed8b408a47 Mon Sep 17 00:00:00 2001
From bd10307b97efc72d331b5fdf56721954e834df48 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg <troglobit@gmail.com>
Date: Thu, 16 Jan 2025 12:35:12 +0100
Subject: [PATCH 26/33] net: dsa: mv88e6xxx: collapse disabled state into
@@ -1,4 +1,4 @@
From 6a87d9cd29e08b0b322233d35621d90470a974e6 Mon Sep 17 00:00:00 2001
From 85b575912a77253cc45a8a50d75999b34ab8aa43 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz <tobias@waldekranz.com>
Date: Wed, 12 Feb 2025 22:03:14 +0100
Subject: [PATCH 27/33] net: dsa: mv88e6xxx: Only activate LAG offloading when
@@ -1,4 +1,4 @@
From d98d5f87b9f5202c55864da0f8a6e9b63a123d2e Mon Sep 17 00:00:00 2001
From 971b21f938d66b6c6f1f5d54b20c4d732e5cf3d6 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Wed, 14 Jan 2026 18:22:41 +0100
Subject: [PATCH 28/33] net: dsa: mv88e6xxx: Add LED support for 6393X
@@ -1,4 +1,4 @@
From f844b2470f23814f3d98c22fc1958958155f2370 Mon Sep 17 00:00:00 2001
From 86a58b0b4b1d60d40a80f058e4f09c87da4093b4 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Thu, 15 Jan 2026 22:47:37 +0100
Subject: [PATCH 29/33] wifi: brcmfmac: support deletion and recreation of
@@ -1,4 +1,4 @@
From 58dcf72c338bd0248dad8105a4169be926d19be2 Mon Sep 17 00:00:00 2001
From 924750050148d937cf62e94f4a706a0be6f5ed02 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Mon, 19 Jan 2026 13:06:53 +0100
Subject: [PATCH 30/33] wifi: brcmfmac: check connection state before querying
@@ -1,4 +1,4 @@
From b408ba43a37bb71f8ea2b83c7f4a4ba0b806f2c7 Mon Sep 17 00:00:00 2001
From 17a580919c5be64b94ccc9e11d0c52b990053485 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Tue, 20 Jan 2026 20:12:10 +0100
Subject: [PATCH 31/33] wifi: brcmfmac: suppress log spam for
@@ -1,4 +1,4 @@
From 2558ffc3abdbbc38a367d6a83c9133e39238339f Mon Sep 17 00:00:00 2001
From 544345cb92b080c77a62eadccb92d07190bac7d1 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Tue, 20 Jan 2026 20:18:45 +0100
Subject: [PATCH 32/33] wifi: brcmfmac: reduce log noise during AP to station
@@ -1,4 +1,4 @@
From fdfab37c4e5c375c204c797f77f91ee6edcbe983 Mon Sep 17 00:00:00 2001
From 5a1dbf99922519d4c36b93c16128c4419da35f30 Mon Sep 17 00:00:00 2001
From: Mattias Walström <lazzer@gmail.com>
Date: Tue, 17 Feb 2026 21:59:59 +0100
Subject: [PATCH 33/33] net: phy: air_en8811h: add OF device table for
+1 -1
View File
@@ -1,2 +1,2 @@
# Calculated with utils/kernel-refresh.sh
sha256 7c716216c3c4134ed0de69195701e677577bbcdd3979f331c182acd06bf2f170 linux-6.18.15.tar.xz
sha256 4f21c01f4d04c1d1b3ed794153f8900802c92497be620b07c4869530f2d28ee3 linux-6.18.16.tar.xz
+8
View File
@@ -46,6 +46,10 @@ AC_ARG_ENABLE(wifi,
AS_HELP_STRING([--enable-wifi], [Enable support for Wi-Fi]),,[
enable_wifi=no])
AC_ARG_ENABLE(gps,
AS_HELP_STRING([--enable-gps], [Enable support for GPS receivers]),,[
enable_gps=no])
AC_ARG_WITH(login-shell,
AS_HELP_STRING([--with-login-shell=shell], [Login shell for new users, default: /bin/false]),
[login_shell=$withval], [login_shell=yes])
@@ -60,6 +64,9 @@ AS_IF([test "x$enable_containers" = "xyes"], [
AS_IF([test "x$enable_wifi" = "xyes"], [
AC_DEFINE(HAVE_WIFI, 1, [Built with Wi-Fi support])])
AS_IF([test "x$enable_gps" = "xyes"], [
AC_DEFINE(HAVE_GPS, 1, [Built with GPS receiver support])])
AS_IF([test "x$with_login_shell" != "xno"], [
AS_IF([test "x$login_shell" = "xyes"], [login_shell=/bin/false])
AC_DEFINE_UNQUOTED(LOGIN_SHELL, "$login_shell", [Default: /bin/false])],[
@@ -131,6 +138,7 @@ cat <<EOF
Optional features:
Container support ....: $enable_containers
Wi-Fi support ........: $enable_wifi
GPS support ..........: $enable_gps
Login shell ..........: $login_shell
Default crypt algo ...: $crypt
+35 -1
View File
@@ -154,6 +154,17 @@ int parse_rip(sr_session_ctx_t *session, struct lyd_node *rip, FILE *fp)
return num_interfaces;
}
static const char *ospf_network_type(const char *yang_type)
{
if (!strcmp(yang_type, "hybrid"))
return "point-to-multipoint";
if (!strcmp(yang_type, "point-to-multipoint"))
return "point-to-multipoint non-broadcast";
/* broadcast, non-broadcast, point-to-point pass through unchanged */
return yang_type;
}
int parse_ospf_interfaces(sr_session_ctx_t *session, struct lyd_node *areas, FILE *fp)
{
struct lyd_node *interface, *interfaces, *area;
@@ -203,7 +214,7 @@ int parse_ospf_interfaces(sr_session_ctx_t *session, struct lyd_node *areas, FIL
if (passive)
fputs(" ip ospf passive\n", fp);
if (interface_type)
fprintf(fp, " ip ospf network %s\n", interface_type);
fprintf(fp, " ip ospf network %s\n", ospf_network_type(interface_type));
if (cost)
fprintf(fp, " ip ospf cost %s\n", cost);
}
@@ -226,6 +237,28 @@ int parse_ospf_redistribute(sr_session_ctx_t *session, struct lyd_node *redistri
return 0;
}
static void parse_ospf_static_neighbors(struct lyd_node *areas, FILE *fp)
{
struct lyd_node *area, *interface, *interfaces, *neighbors, *neighbor;
LY_LIST_FOR(lyd_child(areas), area) {
interfaces = lydx_get_child(area, "interfaces");
LY_LIST_FOR(lyd_child(interfaces), interface) {
neighbors = lydx_get_child(interface, "static-neighbors");
if (!neighbors)
continue;
LY_LIST_FOR(lyd_child(neighbors), neighbor) {
const char *id = lydx_get_cattr(neighbor, "identifier");
if (id)
fprintf(fp, " neighbor %s\n", id);
}
}
}
}
int parse_ospf_areas(sr_session_ctx_t *session, struct lyd_node *areas, FILE *fp)
{
int areas_configured = 0;
@@ -315,6 +348,7 @@ int parse_ospf(sr_session_ctx_t *session, struct lyd_node *ospf)
fputs("router ospf\n", fp);
num_areas = parse_ospf_areas(session, areas, fp);
parse_ospf_redistribute(session, lydx_get_child(ospf, "redistribute"), fp);
parse_ospf_static_neighbors(areas, fp);
default_route = lydx_get_child(ospf, "default-route-advertise");
if (default_route) {
/* enable is obsolete in favor for enabled. */
+2 -2
View File
@@ -14,7 +14,7 @@ MODULES=(
"ietf-routing@2018-03-13.yang"
"ietf-ipv6-unicast-routing@2018-03-13.yang"
"ietf-ipv4-unicast-routing@2018-03-13.yang"
"ietf-ospf@2022-10-19.yang -e bfd -e explicit-router-id"
"ietf-ospf@2022-10-19.yang -e bfd -e explicit-router-id -e hybrid-interface"
"ietf-rip@2020-02-20.yang"
"iana-bfd-types@2021-10-21.yang"
"ietf-bfd-types@2022-09-22.yang"
@@ -31,7 +31,7 @@ MODULES=(
"ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2025-11-02.yang"
"infix-if-type@2026-01-07.yang"
"infix-routing@2025-12-02.yang"
"infix-routing@2026-03-11.yang"
"ieee802-dot1ab-lldp@2022-03-15.yang"
"infix-lldp@2025-05-05.yang"
"infix-dhcp-common@2025-12-21.yang"
+11
View File
@@ -45,6 +45,13 @@ module infix-hardware {
description "Initial";
reference "internal";
}
feature wifi {
description "WiFi support is an optional build-time feature in Infix.";
}
feature gps {
description "GPS support is an optional build-time feature in Infix.";
}
typedef country-code {
type string {
@@ -104,11 +111,13 @@ module infix-hardware {
description "This identity is used to a VPD memory on the device.";
}
identity wifi {
if-feature wifi;
base iahw:hardware-class;
description "This identity is used to describe a WiFi radio/PHY";
}
identity gps {
if-feature gps;
base iahw:hardware-class;
description "GPS/GNSS receiver for time synchronization";
}
@@ -211,6 +220,7 @@ module infix-hardware {
*/
container wifi-radio {
if-feature wifi;
when "derived-from-or-self(../iehw:class, 'ih:wifi')";
presence "WiFi radio configuration";
description
@@ -534,6 +544,7 @@ module infix-hardware {
*/
container gps-receiver {
if-feature gps;
when "derived-from-or-self(../iehw:class, 'ih:gps')";
presence "GPS receiver configuration";
description
+12 -20
View File
@@ -26,6 +26,12 @@ module infix-routing {
contact "kernelkit@googlegroups.com";
description "Deviations and augments for ietf-routing, ietf-ospf, and ietf-rip.";
revision 2026-03-11 {
description "Remove interface-type deviation to expose standard ietf-ospf
interface types including point-to-multipoint and hybrid.
Un-deviate static-neighbors for non-broadcast P2MP support.";
}
revision 2025-12-02 {
description "Add configurable OSPF debug logging container.
Add RIP (Routing Information Protocol) support.";
@@ -247,18 +253,6 @@ module infix-routing {
}
/* OSPF */
typedef infix-ospf-interface-type {
type enumeration {
enum broadcast {
description
"Specifies an OSPF broadcast multi-access network.";
}
enum point-to-point {
description
"Specifies an OSPF point-to-point network.";
}
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol" {
@@ -367,11 +361,6 @@ module infix-routing {
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:areas/ospf:area/ospf:interfaces/ospf:interface/ospf:interface-type" {
deviate replace {
type infix-ospf-interface-type;
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:auto-cost" {
deviate not-supported;
@@ -463,9 +452,12 @@ module infix-routing {
}
/* OSPF Area Interface */
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:areas/ospf:area/ospf:interfaces/ospf:interface/ospf:static-neighbors"
{
deviate not-supported;
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:areas/ospf:area/ospf:interfaces/ospf:interface/ospf:static-neighbors/ospf:neighbor" {
deviate add {
must "../../ospf:interface-type = 'point-to-multipoint' or ../../ospf:interface-type = 'non-broadcast'" {
error-message "Static neighbors are only applicable to point-to-multipoint or non-broadcast interface types.";
}
}
}
deviation "/rt:routing/rt:control-plane-protocols/rt:control-plane-protocol/ospf:ospf/ospf:areas/ospf:area/ospf:interfaces/ospf:interface/ospf:multi-areas" {
deviate not-supported;
+3
View File
@@ -0,0 +1,3 @@
MODULES=(
"infix-hardware -e gps"
)
+1
View File
@@ -1,4 +1,5 @@
MODULES=(
"infix-interfaces -e wifi"
"infix-hardware -e wifi"
"infix-if-type -e wifi"
)
+39 -16
View File
@@ -4832,7 +4832,7 @@ def show_ospf_interfaces(json_data):
state = target_iface.get('state', 'down')
cost = target_iface.get('cost', 0)
priority = target_iface.get('priority', 1)
iface_type = target_iface.get('interface-type', 'unknown')
iface_type = target_iface.get('interface-type', '')
hello_interval = target_iface.get('hello-interval', 10)
dead_interval = target_iface.get('dead-interval', 40)
retransmit_interval = target_iface.get('retransmit-interval', 5)
@@ -4908,9 +4908,11 @@ def show_ospf_interfaces(json_data):
network_type_map = {
'point-to-point': 'POINTOPOINT',
'broadcast': 'BROADCAST',
'non-broadcast': 'NBMA'
'non-broadcast': 'NBMA',
'point-to-multipoint': 'POINTOMULTIPOINT',
'hybrid': 'POINTOMULTIPOINT'
}
network_type = network_type_map.get(iface_type, iface_type.upper())
network_type = network_type_map.get(iface_type, iface_type.upper() if iface_type else 'LOOPBACK')
print(f"{name} is up")
if ip_address:
@@ -4950,30 +4952,50 @@ def show_ospf_interfaces(json_data):
return
# Display table view (no specific interface)
hdr = f"{'INTERFACE':<12} {'AREA':<12} {'STATE':<10} {'COST':<6} {'PRI':<4} {'DR':<15} {'BDR':<15} {'NBRS':<5}"
print(Decore.invert(hdr))
type_display_map = {
'point-to-point': 'P2P',
'broadcast': 'Broadcast',
'non-broadcast': 'NBMA',
'point-to-multipoint': 'P2MP',
'hybrid': 'Hybrid'
}
def fmt_state(state):
if state in ('dr', 'bdr'):
return state.upper()
if state == 'dr-other':
return 'DROther'
return state.capitalize()
table = SimpleTable([
Column('INTERFACE'),
Column('AREA'),
Column('TYPE'),
Column('STATE'),
Column('COST', 'right'),
Column('PRI', 'right'),
Column('DR'),
Column('BDR'),
Column('NBRS', 'right')
])
for iface in all_interfaces:
name = iface.get('name', 'unknown')
area_id = iface.get('_area_id', '0.0.0.0')
state = iface.get('state', 'down')
iface_type = iface.get('interface-type', '')
cost = iface.get('cost', 0)
priority = iface.get('priority', 1)
dr_id = iface.get('dr-router-id', '-')
bdr_id = iface.get('bdr-router-id', '-')
neighbors = iface.get('neighbors', {}).get('neighbor', [])
nbr_count = len(neighbors)
# Capitalize state nicely
state_display = state.upper() if state in ['dr', 'bdr'] else state.capitalize()
if state == 'dr-other':
state_display = 'DROther'
table.row(name, area_id,
type_display_map.get(iface_type, iface_type.capitalize() if iface_type else '-'),
fmt_state(state),
cost, priority, dr_id, bdr_id, len(neighbors))
# Shorten router IDs for display
dr_display = dr_id if dr_id != '-' else '-'
bdr_display = bdr_id if bdr_id != '-' else '-'
print(f"{name:<12} {area_id:<12} {state_display:<10} {cost:<6} {priority:<4} {dr_display:<15} {bdr_display:<15} {nbr_count:<5}")
table.print()
def show_ospf_neighbor(json_data):
@@ -5527,7 +5549,8 @@ def main():
global UNIT_TEST
try:
json_data = json.load(sys.stdin)
raw = sys.stdin.read()
json_data = json.loads(raw) if raw.strip() else {}
except json.JSONDecodeError:
print("Error, invalid JSON input")
sys.exit(1)
+8 -1
View File
@@ -124,8 +124,15 @@ def add_areas(control_protocols):
interface["enabled"] = iface["ospfEnabled"]
if iface["networkType"] == "POINTOPOINT":
interface["interface-type"] = "point-to-point"
if iface["networkType"] == "BROADCAST":
elif iface["networkType"] == "BROADCAST":
interface["interface-type"] = "broadcast"
elif iface["networkType"] == "POINTOMULTIPOINT":
if iface.get("p2mpNonBroadcast", False):
interface["interface-type"] = "point-to-multipoint"
else:
interface["interface-type"] = "hybrid"
elif iface["networkType"] == "NBMA":
interface["interface-type"] = "non-broadcast"
if iface.get("state"):
# Wev've never seen "DependUpon", and has no entry in
+1 -1
View File
@@ -8,7 +8,7 @@ Firewall configuration suitable for end devices on untrusted networks.
image::basic.svg[align=center, scaledwidth=50%]
- Single zone configuration, "public", with action=drop
- Single zone configuration, "public-untrusted-net", with `action=drop`
- Allowed services: SSH (port 22), DHCPv6-client, mySSH (custom, port 222)
- All other ports (HTTP, HTTPS, Telnet, etc.) blocked
- Check that unused interfaces are automatically assigned to default zone
+12 -10
View File
@@ -5,7 +5,7 @@ Firewall configuration suitable for end devices on untrusted networks.
image::basic.svg[align=center, scaledwidth=50%]
- Single zone configuration, "public", with action=drop
- Single zone configuration, "public-untrusted-net", with `action=drop`
- Allowed services: SSH (port 22), DHCPv6-client, mySSH (custom, port 222)
- All other ports (HTTP, HTTPS, Telnet, etc.) blocked
- Check that unused interfaces are automatically assigned to default zone
@@ -47,7 +47,7 @@ with infamy.Test() as test:
target.put_config_dict("infix-firewall", {
"firewall": {
"default": "public",
"default": "public-untrusted-net",
"logging": "all",
"service": [{
"name": "mySSH",
@@ -69,7 +69,9 @@ with infamy.Test() as test:
"interface": [mgmt_if],
"service": ["ssh", "netconf", "restconf"]
}, {
"name": "public",
# 20-char name, exceeds old iptables-derived 17-char limit
# Verifies we allow long names with nftables, issue #1389
"name": "public-untrusted-net",
"description": "Public untrusted network",
"action": "drop",
"interface": [data_if],
@@ -80,7 +82,7 @@ with infamy.Test() as test:
# Wait for configuration to be activated
infamy.Firewall.wait_for_operational(target, {
"public": {"action": "drop"},
"public-untrusted-net": {"action": "drop"},
"mgmt": {"action": "accept"}
})
@@ -88,7 +90,7 @@ with infamy.Test() as test:
data = target.get_data("/infix-firewall:firewall")
fw = data["firewall"]
assert fw["default"] == "public"
assert fw["default"] == "public-untrusted-net"
services = {svc["name"]: svc for svc in fw.get("service", [])}
assert "mySSH" in services, "Custom service mySSH not found"
@@ -106,8 +108,8 @@ with infamy.Test() as test:
assert int(port_entry["lower"]) == 8080
zones = {zone["name"]: zone for zone in fw["zone"]}
assert "public" in zones, "Public zone not found in configuration"
public_zone = zones["public"]
assert "public-untrusted-net" in zones, "public-untrusted-net zone not found in configuration"
public_zone = zones["public-untrusted-net"]
assert public_zone["action"] == "drop"
assert data_if in public_zone["interface"]
assert "ssh" in public_zone["service"]
@@ -119,13 +121,13 @@ with infamy.Test() as test:
data = target.get_data("/infix-firewall:firewall")
fw = data["firewall"]
assert fw["default"] == "public", "Default zone should be 'public'"
assert fw["default"] == "public-untrusted-net", "Default zone should be 'public-untrusted-net'"
zones = {zone["name"]: zone for zone in fw["zone"]}
public_zone = zones["public"]
public_zone = zones["public-untrusted-net"]
assert unused_if in public_zone["interface"], \
f"Unused interface {unused_if} should be in default zone 'public', got interfaces: {public_zone['interface']}"
f"Unused interface {unused_if} should be in default zone 'public-untrusted-net', got interfaces: {public_zone['interface']}"
with infamy.IsolatedMacVlan(host_data) as ns:
ns.addip(HOST_IP)
+10
View File
@@ -10,6 +10,8 @@ Tests verifying standard routing protocols and configuration:
- OSPF with BFD (Bidirectional Forwarding Detection)
- OSPF default route advertisement and propagation
- OSPF debug logging configuration and verification
- OSPF point-to-multipoint hybrid (broadcast) interface type
- OSPF point-to-multipoint (non-broadcast) interface type with static neighbors
- RIP basic neighbor discovery and route exchange
- RIP passive interface configuration
- RIP route redistribution (connected, static, and OSPF)
@@ -46,6 +48,14 @@ include::ospf_debug/Readme.adoc[]
<<<
include::ospf_point_to_multipoint_hybrid/Readme.adoc[]
<<<
include::ospf_point_to_multipoint/Readme.adoc[]
<<<
include::rip_basic/Readme.adoc[]
<<<
+6
View File
@@ -29,6 +29,12 @@
- name: OSPF Debug Logging
case: ospf_debug/test.py
- name: OSPF Point-to-Multipoint Hybrid
case: ospf_point_to_multipoint_hybrid/test.py
- name: OSPF Point-to-Multipoint
case: ospf_point_to_multipoint/test.py
- name: RIP Basic
case: rip_basic/test.py
@@ -0,0 +1 @@
test.adoc
@@ -0,0 +1,49 @@
=== OSPF Point-to-Multipoint
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/ospf_point_to_multipoint]
==== Description
Verify OSPF point-to-multipoint (non-broadcast) interface type by
configuring three routers on a shared multi-access network with the
ietf-ospf 'point-to-multipoint' interface type and static neighbors.
This maps to FRR's 'point-to-multipoint non-broadcast' network type,
which requires manual neighbor configuration since there is no
multicast neighbor discovery.
R2 acts as the hub, bridging two physical links (link1, link2) into a
single broadcast domain (br0). R1 and R3 each connect to one of R2's
ports. The test verifies that all routers form OSPF adjacencies via
unicast, exchange routes, and that the interface type is correctly
reported as point-to-multipoint.
....
+------------------+ +------------------+
| R1 | | R3 |
| 10.0.1.1/32 | | 10.0.3.1/32 |
| (lo) | | (lo) |
+--------+---------+ +--------+---------+
| .1 | .3
| +------------------+ |
+----link1------+ R2 +------link2--------+
| 10.0.2.1/32 |
| (lo) |
| br0: 10.0.123.2 |
+------------------+
10.0.123.0/24
(P2MP non-broadcast / shared segment)
....
==== Topology
image::topology.svg[OSPF Point-to-Multipoint topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUTs
. Configure targets
. Wait for OSPF routes
. Verify interface type is point-to-multipoint
. Verify connectivity between all DUTs
+341
View File
@@ -0,0 +1,341 @@
#!/usr/bin/env python3
"""OSPF Point-to-Multipoint
Verify OSPF point-to-multipoint (non-broadcast) interface type by
configuring three routers on a shared multi-access network with the
ietf-ospf 'point-to-multipoint' interface type and static neighbors.
This maps to FRR's 'point-to-multipoint non-broadcast' network type,
which requires manual neighbor configuration since there is no
multicast neighbor discovery.
R2 acts as the hub, bridging two physical links (link1, link2) into a
single broadcast domain (br0). R1 and R3 each connect to one of R2's
ports. The test verifies that all routers form OSPF adjacencies via
unicast, exchange routes, and that the interface type is correctly
reported as point-to-multipoint.
....
+------------------+ +------------------+
| R1 | | R3 |
| 10.0.1.1/32 | | 10.0.3.1/32 |
| (lo) | | (lo) |
+--------+---------+ +--------+---------+
| .1 | .3
| +------------------+ |
+----link1------+ R2 +------link2--------+
| 10.0.2.1/32 |
| (lo) |
| br0: 10.0.123.2 |
+------------------+
10.0.123.0/24
(P2MP non-broadcast / shared segment)
....
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_target1(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.1",
"prefix-length": 24
}]
}
},
{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.10.1",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.1.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"hello-interval": 1,
"dead-interval": 3,
"interface-type": "point-to-multipoint",
"static-neighbors": {
"neighbor": [
{"identifier": "10.0.123.2"},
{"identifier": "10.0.123.3"}
]
}
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
def config_target2(target, link1, link2):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": "br0",
"type": "infix-if-type:bridge",
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.2",
"prefix-length": 24
}]
}
},
{
"name": link1,
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
},
{
"name": link2,
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.2.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": "br0",
"enabled": True,
"hello-interval": 1,
"dead-interval": 3,
"interface-type": "point-to-multipoint",
"static-neighbors": {
"neighbor": [
{"identifier": "10.0.123.1"},
{"identifier": "10.0.123.3"}
]
}
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
def config_target3(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.3",
"prefix-length": 24
}]
}
},
{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.30.1",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.3.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"hello-interval": 1,
"dead-interval": 3,
"interface-type": "point-to-multipoint",
"static-neighbors": {
"neighbor": [
{"identifier": "10.0.123.1"},
{"identifier": "10.0.123.2"}
]
}
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
R1 = env.attach("R1", "mgmt")
R2 = env.attach("R2", "mgmt")
R3 = env.attach("R3", "mgmt")
with test.step("Configure targets"):
_, R1link = env.ltop.xlate("R1", "link")
_, R1data = env.ltop.xlate("R1", "data")
_, R2link1 = env.ltop.xlate("R2", "link1")
_, R2link2 = env.ltop.xlate("R2", "link2")
_, R3link = env.ltop.xlate("R3", "link")
_, R3data = env.ltop.xlate("R3", "data")
parallel(config_target1(R1, R1link, R1data),
config_target2(R2, R2link1, R2link2),
config_target3(R3, R3link, R3data))
with test.step("Wait for OSPF routes"):
print("Waiting for OSPF routes from all routers")
until(lambda: route.ipv4_route_exist(R1, "10.0.2.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R1, "10.0.3.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "10.0.1.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "10.0.3.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R3, "10.0.1.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R3, "10.0.2.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
with test.step("Verify interface type is point-to-multipoint"):
print("Checking OSPF interface type on all routers")
assert route.ospf_get_interface_type(R1, "0.0.0.0", R1link) == "point-to-multipoint"
assert route.ospf_get_interface_type(R2, "0.0.0.0", "br0") == "point-to-multipoint"
assert route.ospf_get_interface_type(R3, "0.0.0.0", R3link) == "point-to-multipoint"
with test.step("Verify connectivity between all DUTs"):
_, hport1 = env.ltop.xlate("PC", "data1")
_, hport2 = env.ltop.xlate("PC", "data2")
with infamy.IsolatedMacVlan(hport1) as ns1, \
infamy.IsolatedMacVlan(hport2) as ns2:
ns1.addip("10.0.10.2")
ns2.addip("10.0.30.2")
ns1.addroute("10.0.3.1/32", "10.0.10.1")
ns2.addroute("10.0.1.1/32", "10.0.30.1")
parallel(
lambda: ns1.must_reach("10.0.3.1"),
lambda: ns2.must_reach("10.0.1.1"),
)
test.succeed()
@@ -0,0 +1,39 @@
graph "3x1" {
layout="neato";
overlap="false";
esep="+20";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data1> data1 | \n\n\n\n | <mgmt2> mgmt2 | <mgmt3> mgmt3 | <data2> data2 }",
pos="20,30!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link } | R1 \n 10.0.1.1/32 \n(lo)",
pos="160,60!",
requires="infix",
];
R2 [
label="{ <link1> link1 | <mgmt> mgmt | <link2> link2 } | R2 \n 10.0.2.1/32 \n(lo) \n(br0: 10.0.123.2/24)",
pos="160,30!",
requires="infix",
];
R3 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R3 \n 10.0.3.1/32 \n(lo)",
pos="160,0!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt3 -- R3:mgmt [requires="mgmt", color="lightgray"]
PC:data1 -- R1:data [taillabel="10.0.10.2/24", headlabel="10.0.10.1/24"]
R3:data -- PC:data2 [taillabel="10.0.30.1/24", headlabel="10.0.30.2/24"]
R1:link -- R2:link1 [taillabel="10.0.123.1/24"]
R3:link -- R2:link2 [taillabel="10.0.123.3/24"]
}
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: 3x1 Pages: 1 -->
<svg width="720pt" height="312pt"
viewBox="0.00 0.00 720.00 312.15" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(0.98 0.98) rotate(0) translate(4 314.02)">
<title>3x1</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-314.02 729.56,-314.02 729.56,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-61.51 0,-248.51 91,-248.51 91,-61.51 0,-61.51"/>
<text text-anchor="middle" x="16.5" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-61.51 33,-248.51 "/>
<text text-anchor="middle" x="62" y="-233.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-225.51 91,-225.51 "/>
<text text-anchor="middle" x="62" y="-210.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
<polyline fill="none" stroke="black" points="33,-202.51 91,-202.51 "/>
<polyline fill="none" stroke="black" points="33,-130.51 91,-130.51 "/>
<text text-anchor="middle" x="62" y="-115.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
<polyline fill="none" stroke="black" points="33,-107.51 91,-107.51 "/>
<text text-anchor="middle" x="62" y="-92.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
<polyline fill="none" stroke="black" points="33,-84.51 91,-84.51 "/>
<text text-anchor="middle" x="62" y="-69.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="518.56,-240.52 518.56,-309.52 692.56,-309.52 692.56,-240.52 518.56,-240.52"/>
<text text-anchor="middle" x="543.56" y="-294.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="518.56,-286.52 568.56,-286.52 "/>
<text text-anchor="middle" x="543.56" y="-271.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="518.56,-263.52 568.56,-263.52 "/>
<text text-anchor="middle" x="543.56" y="-248.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="568.56,-240.52 568.56,-309.52 "/>
<text text-anchor="middle" x="630.56" y="-286.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="630.56" y="-271.32" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.1.1/32 </text>
<text text-anchor="middle" x="630.56" y="-256.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-237.01C91.5,-237.01 518.56,-298.02 518.56,-298.02"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge4" class="edge">
<title>PC:data1&#45;&#45;R1:data</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M91.5,-214.01C91.5,-214.01 518.56,-275.02 518.56,-275.02"/>
<text text-anchor="middle" x="473.06" y="-278.82" font-family="DejaVu Serif, Book" font-size="14.00">10.0.10.1/24</text>
<text text-anchor="middle" x="137" y="-217.81" font-family="DejaVu Serif, Book" font-size="14.00">10.0.10.2/24</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="485.56,-120.51 485.56,-189.51 725.56,-189.51 725.56,-120.51 485.56,-120.51"/>
<text text-anchor="middle" x="514.56" y="-174.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link1</text>
<polyline fill="none" stroke="black" points="485.56,-166.51 543.56,-166.51 "/>
<text text-anchor="middle" x="514.56" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="485.56,-143.51 543.56,-143.51 "/>
<text text-anchor="middle" x="514.56" y="-128.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link2</text>
<polyline fill="none" stroke="black" points="543.56,-120.51 543.56,-189.51 "/>
<text text-anchor="middle" x="634.56" y="-173.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="634.56" y="-158.81" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.2.1/32 </text>
<text text-anchor="middle" x="634.56" y="-143.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo) </text>
<text text-anchor="middle" x="634.56" y="-128.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(br0: 10.0.123.2/24)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-119.01C91.5,-119.01 485.56,-155.01 485.56,-155.01"/>
</g>
<!-- R3 -->
<g id="node4" class="node">
<title>R3</title>
<polygon fill="none" stroke="black" points="518.56,-0.5 518.56,-69.5 692.56,-69.5 692.56,-0.5 518.56,-0.5"/>
<text text-anchor="middle" x="543.56" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="518.56,-46.5 568.56,-46.5 "/>
<text text-anchor="middle" x="543.56" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="518.56,-23.5 568.56,-23.5 "/>
<text text-anchor="middle" x="543.56" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="568.56,-0.5 568.56,-69.5 "/>
<text text-anchor="middle" x="630.56" y="-46.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R3 </text>
<text text-anchor="middle" x="630.56" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.3.1/32 </text>
<text text-anchor="middle" x="630.56" y="-16.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R3 -->
<g id="edge3" class="edge">
<title>PC:mgmt3&#45;&#45;R3:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-96.01C91.5,-96.01 518.56,-35 518.56,-35"/>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge6" class="edge">
<title>R1:link&#45;&#45;R2:link1</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M543.56,-240.02C543.56,-240.02 514.56,-190.01 514.56,-190.01"/>
<text text-anchor="middle" x="493.56" y="-228.82" font-family="DejaVu Serif, Book" font-size="14.00">10.0.123.1/24</text>
</g>
<!-- R3&#45;&#45;PC -->
<g id="edge5" class="edge">
<title>R3:data&#45;&#45;PC:data2</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M518.56,-12C518.56,-12 91.5,-73.01 91.5,-73.01"/>
<text text-anchor="middle" x="137" y="-76.81" font-family="DejaVu Serif, Book" font-size="14.00">10.0.30.2/24</text>
<text text-anchor="middle" x="473.06" y="-15.8" font-family="DejaVu Serif, Book" font-size="14.00">10.0.30.1/24</text>
</g>
<!-- R3&#45;&#45;R2 -->
<g id="edge7" class="edge">
<title>R3:link&#45;&#45;R2:link2</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M543.56,-70C543.56,-70 514.56,-120.01 514.56,-120.01"/>
<text text-anchor="middle" x="493.56" y="-73.8" font-family="DejaVu Serif, Book" font-size="14.00">10.0.123.3/24</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -0,0 +1 @@
test.adoc
@@ -0,0 +1,46 @@
=== OSPF Point-to-Multipoint Hybrid
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/routing/ospf_point_to_multipoint_hybrid]
==== Description
Verify OSPF point-to-multipoint hybrid (broadcast) interface type by
configuring three routers on a shared multi-access network with the
ietf-ospf 'hybrid' interface type. This maps to FRR's 'point-to-multipoint'
network type, which uses multicast for neighbor discovery.
R2 acts as the hub, bridging two physical links (link1, link2) into a
single broadcast domain (br0). R1 and R3 each connect to one of R2's
ports. The test verifies that all routers form OSPF adjacencies, exchange
routes, and that the interface type is correctly reported as hybrid.
....
+------------------+ +------------------+
| R1 | | R3 |
| 10.0.1.1/32 | | 10.0.3.1/32 |
| (lo) | | (lo) |
+--------+---------+ +--------+---------+
| .1 | .3
| +------------------+ |
+----link1------+ R2 +------link2--------+
| 10.0.2.1/32 |
| (lo) |
| br0: 10.0.123.2 |
+------------------+
10.0.123.0/24
(P2MP hybrid / shared segment)
....
==== Topology
image::topology.svg[OSPF Point-to-Multipoint Hybrid topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUTs
. Configure targets
. Wait for OSPF routes
. Verify interface type is hybrid
. Verify connectivity between all DUTs
+334
View File
@@ -0,0 +1,334 @@
#!/usr/bin/env python3
"""OSPF Point-to-Multipoint Hybrid
Verify OSPF point-to-multipoint hybrid (broadcast) interface type by
configuring three routers on a shared multi-access network with the
ietf-ospf 'hybrid' interface type. This maps to FRR's 'point-to-multipoint'
network type, which uses multicast for neighbor discovery.
R2 acts as the hub, bridging two physical links (link1, link2) into a
single broadcast domain (br0). R1 and R3 each connect to one of R2's
ports. The test verifies that all routers form OSPF adjacencies, exchange
routes, and that the interface type is correctly reported as hybrid.
....
+------------------+ +------------------+
| R1 | | R3 |
| 10.0.1.1/32 | | 10.0.3.1/32 |
| (lo) | | (lo) |
+--------+---------+ +--------+---------+
| .1 | .3
| +------------------+ |
+----link1------+ R2 +------link2--------+
| 10.0.2.1/32 |
| (lo) |
| br0: 10.0.123.2 |
+------------------+
10.0.123.0/24
(P2MP hybrid / shared segment)
....
"""
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_target1(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.1",
"prefix-length": 24
}]
}
},
{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.10.1",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.1.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-system": {
"system": {
"hostname": "R1"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"interface-type": "hybrid",
"hello-interval": 1,
"dead-interval": 3
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
def config_target2(target, link1, link2):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": "br0",
"type": "infix-if-type:bridge",
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.2",
"prefix-length": 24
}]
}
},
{
"name": link1,
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
},
{
"name": link2,
"enabled": True,
"infix-interfaces:bridge-port": {
"bridge": "br0"
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.2.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-system": {
"system": {
"hostname": "R2"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": "br0",
"enabled": True,
"interface-type": "hybrid",
"hello-interval": 1,
"dead-interval": 3
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
def config_target3(target, link, data):
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.123.3",
"prefix-length": 24
}]
}
},
{
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "10.0.30.1",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.3.1",
"prefix-length": 32
}]
}
}
]
}
},
"ietf-system": {
"system": {
"hostname": "R3"
}
},
"ietf-routing": {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"interface-type": "hybrid",
"hello-interval": 1,
"dead-interval": 3
}, {
"name": "lo",
"enabled": True
}]
}
}]
}
}
}]
}
}
}
})
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
R1 = env.attach("R1", "mgmt")
R2 = env.attach("R2", "mgmt")
R3 = env.attach("R3", "mgmt")
with test.step("Configure targets"):
_, R1link = env.ltop.xlate("R1", "link")
_, R1data = env.ltop.xlate("R1", "data")
_, R2link1 = env.ltop.xlate("R2", "link1")
_, R2link2 = env.ltop.xlate("R2", "link2")
_, R3link = env.ltop.xlate("R3", "link")
_, R3data = env.ltop.xlate("R3", "data")
parallel(config_target1(R1, R1link, R1data),
config_target2(R2, R2link1, R2link2),
config_target3(R3, R3link, R3data))
with test.step("Wait for OSPF routes"):
print("Waiting for OSPF routes to converge")
until(lambda: route.ipv4_route_exist(R1, "10.0.2.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R1, "10.0.3.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "10.0.1.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "10.0.3.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R3, "10.0.1.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R3, "10.0.2.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
with test.step("Verify interface type is hybrid"):
print("Checking OSPF interface type on all routers")
assert route.ospf_get_interface_type(R1, "0.0.0.0", R1link) == "hybrid"
assert route.ospf_get_interface_type(R2, "0.0.0.0", "br0") == "hybrid"
assert route.ospf_get_interface_type(R3, "0.0.0.0", R3link) == "hybrid"
with test.step("Verify connectivity between all DUTs"):
_, hport1 = env.ltop.xlate("PC", "data1")
_, hport2 = env.ltop.xlate("PC", "data2")
with infamy.IsolatedMacVlan(hport1) as ns1, \
infamy.IsolatedMacVlan(hport2) as ns2:
ns1.addip("10.0.10.2")
ns2.addip("10.0.30.2")
ns1.addroute("10.0.3.1/32", "10.0.10.1")
ns2.addroute("10.0.1.1/32", "10.0.30.1")
parallel(
lambda: ns1.must_reach("10.0.3.1"),
lambda: ns2.must_reach("10.0.1.1"),
)
test.succeed()
@@ -0,0 +1,39 @@
graph "3r-p2mp" {
layout="neato";
overlap="false";
esep="+20";
size=10
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data1> data1 | \n\n\n\n | <mgmt2> mgmt2 | <mgmt3> mgmt3 | <data2> data2 }",
pos="20,30!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link } | R1 \n 10.0.1.1/32 \n(lo)",
pos="160,60!",
requires="infix",
];
R2 [
label="{ <link1> link1 | <mgmt> mgmt | <link2> link2 } | R2 \n 10.0.2.1/32 \n(lo) \n(br0: 10.0.123.2/24)",
pos="160,30!",
requires="infix",
];
R3 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R3 \n 10.0.3.1/32 \n(lo)",
pos="160,0!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt3 -- R3:mgmt [requires="mgmt", color="lightgray"]
PC:data1 -- R1:data [taillabel="10.0.10.2/24", headlabel="10.0.10.1/24"]
R3:data -- PC:data2 [taillabel="10.0.30.1/24", headlabel="10.0.30.2/24"]
R1:link -- R2:link1 [taillabel="10.0.123.1/24"]
R3:link -- R2:link2 [taillabel="10.0.123.3/24"]
}
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: 3r&#45;p2mp Pages: 1 -->
<svg width="720pt" height="312pt"
viewBox="0.00 0.00 720.00 312.15" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(0.98 0.98) rotate(0) translate(4 314.02)">
<title>3r&#45;p2mp</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-314.02 729.56,-314.02 729.56,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-61.51 0,-248.51 91,-248.51 91,-61.51 0,-61.51"/>
<text text-anchor="middle" x="16.5" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-61.51 33,-248.51 "/>
<text text-anchor="middle" x="62" y="-233.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-225.51 91,-225.51 "/>
<text text-anchor="middle" x="62" y="-210.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data1</text>
<polyline fill="none" stroke="black" points="33,-202.51 91,-202.51 "/>
<polyline fill="none" stroke="black" points="33,-130.51 91,-130.51 "/>
<text text-anchor="middle" x="62" y="-115.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
<polyline fill="none" stroke="black" points="33,-107.51 91,-107.51 "/>
<text text-anchor="middle" x="62" y="-92.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
<polyline fill="none" stroke="black" points="33,-84.51 91,-84.51 "/>
<text text-anchor="middle" x="62" y="-69.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data2</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="518.56,-240.52 518.56,-309.52 692.56,-309.52 692.56,-240.52 518.56,-240.52"/>
<text text-anchor="middle" x="543.56" y="-294.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="518.56,-286.52 568.56,-286.52 "/>
<text text-anchor="middle" x="543.56" y="-271.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="518.56,-263.52 568.56,-263.52 "/>
<text text-anchor="middle" x="543.56" y="-248.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="568.56,-240.52 568.56,-309.52 "/>
<text text-anchor="middle" x="630.56" y="-286.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="630.56" y="-271.32" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.1.1/32 </text>
<text text-anchor="middle" x="630.56" y="-256.32" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-237.01C91.5,-237.01 518.56,-298.02 518.56,-298.02"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge4" class="edge">
<title>PC:data1&#45;&#45;R1:data</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M91.5,-214.01C91.5,-214.01 518.56,-275.02 518.56,-275.02"/>
<text text-anchor="middle" x="473.06" y="-278.82" font-family="DejaVu Serif, Book" font-size="14.00">10.0.10.1/24</text>
<text text-anchor="middle" x="137" y="-217.81" font-family="DejaVu Serif, Book" font-size="14.00">10.0.10.2/24</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="485.56,-120.51 485.56,-189.51 725.56,-189.51 725.56,-120.51 485.56,-120.51"/>
<text text-anchor="middle" x="514.56" y="-174.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link1</text>
<polyline fill="none" stroke="black" points="485.56,-166.51 543.56,-166.51 "/>
<text text-anchor="middle" x="514.56" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="485.56,-143.51 543.56,-143.51 "/>
<text text-anchor="middle" x="514.56" y="-128.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link2</text>
<polyline fill="none" stroke="black" points="543.56,-120.51 543.56,-189.51 "/>
<text text-anchor="middle" x="634.56" y="-173.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="634.56" y="-158.81" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.2.1/32 </text>
<text text-anchor="middle" x="634.56" y="-143.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo) </text>
<text text-anchor="middle" x="634.56" y="-128.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(br0: 10.0.123.2/24)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-119.01C91.5,-119.01 485.56,-155.01 485.56,-155.01"/>
</g>
<!-- R3 -->
<g id="node4" class="node">
<title>R3</title>
<polygon fill="none" stroke="black" points="518.56,-0.5 518.56,-69.5 692.56,-69.5 692.56,-0.5 518.56,-0.5"/>
<text text-anchor="middle" x="543.56" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="518.56,-46.5 568.56,-46.5 "/>
<text text-anchor="middle" x="543.56" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="518.56,-23.5 568.56,-23.5 "/>
<text text-anchor="middle" x="543.56" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="568.56,-0.5 568.56,-69.5 "/>
<text text-anchor="middle" x="630.56" y="-46.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R3 </text>
<text text-anchor="middle" x="630.56" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 10.0.3.1/32 </text>
<text text-anchor="middle" x="630.56" y="-16.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R3 -->
<g id="edge3" class="edge">
<title>PC:mgmt3&#45;&#45;R3:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-96.01C91.5,-96.01 518.56,-35 518.56,-35"/>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge6" class="edge">
<title>R1:link&#45;&#45;R2:link1</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M543.56,-240.02C543.56,-240.02 514.56,-190.01 514.56,-190.01"/>
<text text-anchor="middle" x="493.56" y="-228.82" font-family="DejaVu Serif, Book" font-size="14.00">10.0.123.1/24</text>
</g>
<!-- R3&#45;&#45;PC -->
<g id="edge5" class="edge">
<title>R3:data&#45;&#45;PC:data2</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M518.56,-12C518.56,-12 91.5,-73.01 91.5,-73.01"/>
<text text-anchor="middle" x="137" y="-76.81" font-family="DejaVu Serif, Book" font-size="14.00">10.0.30.2/24</text>
<text text-anchor="middle" x="473.06" y="-15.8" font-family="DejaVu Serif, Book" font-size="14.00">10.0.30.1/24</text>
</g>
<!-- R3&#45;&#45;R2 -->
<g id="edge7" class="edge">
<title>R3:link&#45;&#45;R2:link2</title>
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M543.56,-70C543.56,-70 514.56,-120.01 514.56,-120.01"/>
<text text-anchor="middle" x="493.56" y="-73.8" font-family="DejaVu Serif, Book" font-size="14.00">10.0.123.3/24</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB