Compare commits

..
16 Commits
Author SHA1 Message Date
Joachim Wiberg 80659ef299 Final ChangeLog update for v24.04.1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 17:06:15 +02:00
Joachim Wiberg 59b3e583f1 doc: update build deps, bison needed new uboot-tools
The Buildroot 2024.02.x-kkit branch recently had uboot-tools upgraded
and the patches needed require bison to rebuild.

The recommendation is to also install flex, they always go together.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 17:03:03 +02:00
Joachim WibergandMattias Walström 6a8eaacc6e Replace python + rust based gencert2 with C based gencert3
Also, sync r2s_defconfig with latest major changes.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 15:33:00 +02:00
Joachim WibergandMattias Walström 6b8bd4caf3 package/gencert: new package
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 15:33:00 +02:00
Joachim WibergandMattias Walström 39f868fc61 gencert: C replacement for python+rust gencert
Smaller, fewer dependencies, and quicker to cross-compile.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 15:33:00 +02:00
Joachim WibergandMattias Walström be1c00f469 package/factory: add checksum for LICENSE
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 15:33:00 +02:00
Joachim WibergandMattias Walström 71e63de0c1 execd: minor, drop dummy line from configure summary
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 15:33:00 +02:00
Tobias WaldekranzandJoachim Wiberg 6c1c31e5c0 doc: testing: Document how to use deterministic topology mappings 2024-05-03 14:44:54 +02:00
Tobias WaldekranzandJoachim Wiberg a2906acdf7 test: Optionally use deterministic topology mappings
Due to the salting being applied to Python's `hash()` (see [1]), the
hash of an object is not stable across different Python processes. As
a result, neither are the topology mappings generated by networkx.

The upside of this is randomness that we get better test coverage over
time, especially on physical devices where the underlying hardware
could differ between ports, for example.

On the other hand, it can be very frustrating to track down a bug when
locial nodes are suffled around between phyical nodes on each
invocation of a test case.

Therefore, use a random seed by default, but allow the user to specify
a fixed value if they so choose. We then add a meta test that logs the
seed being used for the current suite - which means we can simply
copy&paste that value to rerun the suite (or single test) with the
same topology mappings.

[1]: https://docs.python.org/3/reference/datamodel.html#object.__hash__
2024-05-03 14:44:54 +02:00
Tobias WaldekranzandJoachim Wiberg 753f3806a1 test: Improve efficiency of logical to physical topology matching
- Present the topologies to networkx as multigraphs, rather than
  expaning each port of the record shape as a separate node.

- Create a topology mapping by locating a subgraph monomorphism of the
  logical topology in the physical ditto.

This cuts down the time of finding a mapping by several orders of
magnitude. Example:

Before:

time python3 test/infamy/topology.py \
     	     test/virt/quad/topology.dot.in \
	     test/infamy/topologies/ring-4-duts.dot >/dev/null

real    13m1,213s
user    13m0,112s
sys     0m0,732s

After:

time python3 test/infamy/topology.py \
     	     test/virt/quad/topology.dot.in \
	     test/infamy/topologies/ring-4-duts.dot >/dev/null

real    0m0,153s
user    0m0,128s
sys     0m0,024s
2024-05-03 14:44:54 +02:00
Joachim WibergandTobias Waldekranz 2a218ce6e9 doc: update ChangeLog for v24.04.1
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 07:54:48 +02:00
Joachim WibergandTobias Waldekranz 474820c44b Fix #424: regression, root user can log in without password
This fixes a serious security regression introduced late in the v24.04
release cycle.  The root cause is the placement of the shadow file in
the rootfs overlay, which causes any changes made by the Buildroot
setting BR2_TARGET_ENABLE_ROOT_LOGIN to be discarded/overwritten just
before creating the squashfs image.

The fix in this commit relocates all files from b4eb450 to the skeleton
in Infix, package/skeleton-init-finit/skeleton/etc, which is one of the
first packages to be installed when starting a build.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 07:54:48 +02:00
Joachim WibergandTobias Waldekranz 9609fc144d confd: add timestamps to dagger .log files
Sample output:

    root@infix-00-00-00:~# cat /run/net/0/action/init/lo/45-init.sysctl.log
    May 02 13:45:58 net.ipv6.conf.lo.autoconf = 1
    May 02 13:45:58 net.ipv6.conf.lo.dad_transmits = 1
    May 02 13:45:58 net.ipv6.conf.lo.temp_prefered_lft = 86400
    May 02 13:45:58 net.ipv6.conf.lo.temp_valid_lft = 604800
    May 02 13:45:58 [exit:0]

Fixes #374

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 07:54:48 +02:00
Joachim WibergandTobias Waldekranz a0df130852 board/common: relocate dagger script to confd tree
The dagger tool is a helper for scripts generated by confd and should
therefore be installed by confd instead of the rootfs overlay.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 07:54:48 +02:00
Joachim WibergandTobias Waldekranz 22c911f85e package/landing: new package
Relocate the default landing page from the rootfs overlay to a package
so that customer repos can override it.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-05-03 07:54:48 +02:00
Tobias WaldekranzandJoachim Wiberg 3d8b64f939 aarch64: kernel: Enable DCB
In order to make use of the DCB support in mv88e6xxx we also enable it
in the kernel config.

Fixes: 3a73ce3cfb ("kernel: Import EtherType based priority override support")
2024-05-02 15:30:02 +02:00
43 changed files with 535 additions and 167 deletions
+1
View File
@@ -178,6 +178,7 @@ CONFIG_NET_SCHED=y
CONFIG_NET_CLS_BASIC=y
CONFIG_NET_CLS_BPF=y
CONFIG_NET_CLS_FLOWER=y
CONFIG_DCB=y
CONFIG_NETLINK_DIAG=y
CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=y
-67
View File
@@ -1,67 +0,0 @@
#!/usr/bin/env python3
# Generate a self signed certificate with unlimited expire time
import argparse
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
from datetime import datetime, timedelta
# Generate private key
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
parser = argparse.ArgumentParser(description="Generate a self signed certificate")
parser.add_argument('--country', required=True, help="Set country")
parser.add_argument('--state', required=True, help="Set state or province name")
parser.add_argument('--city', required=True, help="Set city name")
parser.add_argument('--organisation', required=True, help="Set organisation name")
parser.add_argument('--organisation-unit', required=True, help="Set organisation unit name")
parser.add_argument('--common-name', required=True, help="Set common name")
parser.add_argument('--out-certificate', required=True, help="Output certificate")
parser.add_argument('--out-key', required=True, help="Output key")
args = parser.parse_args()
# Builder for certificate
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, args.country),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, args.state),
x509.NameAttribute(NameOID.LOCALITY_NAME, args.city),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, args.organisation),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, args.organisation_unit),
x509.NameAttribute(NameOID.COMMON_NAME, args.common_name),
])
certificate = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
private_key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
datetime(2000, 1, 1)
).not_valid_after(
datetime(9999, 1, 1)
).add_extension(
x509.SubjectAlternativeName([x509.DNSName(args.common_name)]),
critical=False,
).sign(private_key, hashes.SHA256(), default_backend())
# Serialize certificate and private key
with open(args.out_certificate, "wb") as f:
f.write(certificate.public_bytes(serialization.Encoding.PEM))
with open(args.out_key, "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
))
+2 -1
View File
@@ -54,7 +54,6 @@ 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_CRYPTOGRAPHY=y
BR2_PACKAGE_PYTHON_GUNICORN=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
BR2_PACKAGE_LIBSSH2=y
@@ -130,6 +129,7 @@ INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_CURIOS_HTTPD=y
BR2_PACKAGE_EXECD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
@@ -142,6 +142,7 @@ BR2_PACKAGE_IITO=y
BR2_PACKAGE_K8S_LOGGER=y
BR2_PACKAGE_KEYACK=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_LANDING=y
BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
+5 -4
View File
@@ -13,7 +13,7 @@ BR2_TARGET_GENERIC_HOSTNAME="infix"
BR2_TARGET_GENERIC_ISSUE="Infix by KernelKit"
BR2_INIT_FINIT=y
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_ROOTFS_DEVICE_TABLE="system/device_table.txt ${BR2_EXTERNAL_INFIX_PATH}/board/common/xattrs ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/xattrs"
BR2_ROOTFS_DEVICE_TABLE="system/device_table.txt ${BR2_EXTERNAL_INFIX_PATH}/board/common/xattrs"
# BR2_TARGET_ENABLE_ROOT_LOGIN is not set
BR2_SYSTEM_BIN_SH_BASH=y
BR2_TARGET_GENERIC_GETTY_PORT="@console"
@@ -22,8 +22,8 @@ BR2_SYSTEM_DHCP="eth0"
BR2_ENABLE_LOCALE_WHITELIST="C en_US en_CA"
BR2_GENERATE_LOCALE="en_US en_CA"
BR2_TARGET_TZ_INFO=y
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/rootfs"
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/netconf/post-build.sh"
BR2_ROOTFS_OVERLAY="${BR2_EXTERNAL_INFIX_PATH}/board/common/rootfs ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/rootfs"
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/post-build.sh ${BR2_EXTERNAL_INFIX_PATH}/board/common/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="${BR2_EXTERNAL_INFIX_PATH}/board/common/post-image.sh support/scripts/genimage.sh"
BR2_ROOTFS_POST_SCRIPT_ARGS="-c $(BR2_EXTERNAL_INFIX_PATH)/board/aarch64/r2s/genimage.cfg"
BR2_LINUX_KERNEL=y
@@ -64,7 +64,6 @@ 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_CRYPTOGRAPHY=y
BR2_PACKAGE_PYTHON_GUNICORN=y
BR2_PACKAGE_CA_CERTIFICATES=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
@@ -159,6 +158,7 @@ INFIX_DOC="https://github.com/kernelkit/infix/tree/main/doc"
INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_EXECD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
@@ -171,6 +171,7 @@ BR2_PACKAGE_IITO=y
BR2_PACKAGE_K8S_LOGGER=y
BR2_PACKAGE_KEYACK=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_LANDING=y
BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
+2 -1
View File
@@ -49,7 +49,6 @@ 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_CRYPTOGRAPHY=y
BR2_PACKAGE_PYTHON_GUNICORN=y
BR2_PACKAGE_LIBSSH_OPENSSL=y
BR2_PACKAGE_LIBSSH2=y
@@ -133,6 +132,7 @@ INFIX_SUPPORT="mailto:kernelkit@googlegroups.com"
BR2_PACKAGE_CONFD=y
BR2_PACKAGE_CURIOS_HTTPD=y
BR2_PACKAGE_EXECD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
@@ -145,6 +145,7 @@ BR2_PACKAGE_IITO=y
BR2_PACKAGE_K8S_LOGGER=y
BR2_PACKAGE_KEYACK=y
BR2_PACKAGE_KLISH_PLUGIN_INFIX=y
BR2_PACKAGE_LANDING=y
BR2_PACKAGE_LOWDOWN=y
BR2_PACKAGE_MCD=y
BR2_PACKAGE_MDNS_ALIAS=y
+19
View File
@@ -4,6 +4,24 @@ Change Log
All notable changes to the project are documented in this file.
[v24.04.1][] - 2024-05-03
-------------------------
### Changes
- Default web landing page refactored into a Buildroot package to make
it possible to overload from customer repos.
- Enable DCB support in aarch64 kernel (for EtherType prio override)
- Topology mapper improvements, including option for deterministic
reproduction of logical to physical mappings
- New version of `gencert` tool, for self signed HTTPS certificates.
This allows dropping dependency on building a host rust toolchain
- Issue #374: add timestamps to dagger .log files
### Fixes
- Add missing LICENSE hash for factory reset tool
- Fix #424: regression, root user can log in without password
[v24.04.0][] - 2024-04-30
-------------------------
@@ -844,6 +862,7 @@ Supported YANG models in addition to those used by sysrepo and netopeer:
[buildroot]: https://buildroot.org/
[UNRELEASED]: https://github.com/kernelkit/infix/compare/v24.04.0...HEAD
[v24.04.1]: https://github.com/kernelkit/infix/compare/v24.04.0...v24.04.1
[v24.04.0]: https://github.com/kernelkit/infix/compare/v24.02.0...v24.04.0
[v24.02.0]: https://github.com/kernelkit/infix/compare/v23.11.0...v24.02.0
[v23.11.0]: https://github.com/kernelkit/infix/compare/v23.10.0...v23.11.0
+1 -1
View File
@@ -67,7 +67,7 @@ $ sudo apt install bc binutils build-essential bzip2 cpio \
diffutils file findutils git gzip \
libncurses-dev libssl-dev perl patch \
python3 rsync sed tar unzip wget \
autopoint
autopoint bison flex
```
For testing, a few more tools and services are required on your system:
+39
View File
@@ -410,6 +410,45 @@ You can now freely debug the network activity of your test and the
responses from the DUT.
### Deterministic Topology Mappings
By default, mappings from logical to physical topologies are not
stable across test case executions. This can be very frustrating when
debugging a failing test, since logical nodes are suffled around
between phyical nodes. In such cases, supplying a `PYTHONHASHSEED`
variable (set to any 32-bit unsigned integer) when launching the test
environment will make sure that topology mappings are deterministic:
$ make PYTHONHASHSEED=0 test-sh
If a seed is not supplied, a random value is chosen. This seed is
logged by the `meta/reproducible.py` test case when running a test
suite:
$ make test
Info: Generating topology
Info: Generating node YAML
Info: Generating executables
Info: Launching dut1
Info: Launching dut2
Info: Launching dut3
Info: Launching dut4
9PM - Simplicity is the ultimate sophistication
Starting test 0002-reproducible.py
2024-05-03 10:40:30 # Starting (2024-05-03 10:40:30)
2024-05-03 10:40:30 # Specify PYTHONHASHSEED=3773822171 to reproduce this test environment
2024-05-03 10:40:30 ok 1 - $PYTHONHASHSEED is set
2024-05-03 10:40:30 # Exiting (2024-05-03 10:40:30)
2024-05-03 10:40:30 1..1
...
This is useful because this value can then be used to rerun a test (or
the whole suite) with identical topology mappings:
$ make PYTHONHASHSEED=3773822171 INFIX_TESTS=case/ietf_system/hostname.py test
[9PM]: https://github.com/rical/9pm
[Qeneth]: https://github.com/wkz/qeneth
[TAP]: https://testanything.org/
+4 -2
View File
@@ -1,10 +1,12 @@
source "$BR2_EXTERNAL_INFIX_PATH/package/confd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/curios-httpd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/execd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/gencert/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/statd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/factory/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/faux/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/finit/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/greenpak-programmer/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/ifupdown-ng/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/iito/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/k8s-logger/Config.in"
@@ -12,13 +14,13 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/keyack/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-infix/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/klish/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/python-statd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/landing/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/libsrx/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/lowdown/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/mcd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/mdns-alias/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/netbrowse/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/python-statd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/greenpak-programmer/Config.in"
+1
View File
@@ -0,0 +1 @@
sha256 518cd23d81f17b912f1c4ccc6acb67ff614ddcc2caf14def5044126d1a60f364 LICENSE
+8
View File
@@ -0,0 +1,8 @@
config BR2_PACKAGE_GENCERT
bool "gencert"
select BR2_PACKAGE_OPENSSL
help
Generate a self-signed certificate for embedded systems confused
about the current time. Start date: 2000-01-01, end: 9999-01-01
https://github.com/kernelkit/infix
+1
View File
@@ -0,0 +1 @@
sha256 fff5e150e496c6bb6035ae388ee13cf2d0df842335e5145a4b902ef6b7892088 LICENSE
+22
View File
@@ -0,0 +1,22 @@
################################################################################
#
# gencert
#
################################################################################
GENCERT_VERSION = 1.0
GENCERT_SITE_METHOD = local
GENCERT_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/gencert
GENCERT_LICENSE = ISC
GENCERT_LICENSE_FILES = LICENSE
GENCERT_REDISTRIBUTE = NO
GENCERT_DEPENDENCIES = openssl
GENCERT_AUTORECONF = YES
define GENCERT_CONF_ENV
CFLAGS="$(INFIX_CFLAGS)"
endef
GENCERT_CONF_OPTS = --prefix= --disable-silent-rules
$(eval $(autotools-package))
+6
View File
@@ -0,0 +1,6 @@
config BR2_PACKAGE_LANDING
bool "Landing page (temporary)"
help
Temporary landing page before upcoming webui.
https://github.com/kernelkit/infix
+1
View File
@@ -0,0 +1 @@
sha256 fff5e150e496c6bb6035ae388ee13cf2d0df842335e5145a4b902ef6b7892088 LICENSE
+18
View File
@@ -0,0 +1,18 @@
################################################################################
#
# landing
#
################################################################################
LANDING_VERSION = 1.0
LANDING_SITE_METHOD = local
LANDING_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/landing
LANDING_LICENSE = ISC
LANDING_LICENSE_FILES = LICENSE
define LANDING_INSTALL_TARGET_CMDS
cp $(@D)/*.html $(TARGET_DIR)/usr/html/
cp $(@D)/*.png $(TARGET_DIR)/usr/html/
endef
$(eval $(generic-package))
+3 -2
View File
@@ -1,2 +1,3 @@
pkglibexec_SCRIPTS = bootstrap error load gen-service \
gen-hostkeys gen-admin-auth gen-hostname gen-interfaces gen-motd gen-hardware
pkglibexec_SCRIPTS = bootstrap error load gen-service gen-hostkeys gen-admin-auth \
gen-hostname gen-interfaces gen-motd gen-hardware
sbin_SCRIPTS = dagger
@@ -50,8 +50,8 @@ action_exec()
for node in $order; do
for work in $(find "$actdir/$node" -type f -executable 2>/dev/null | sort); do
$work >>"$work.log" 2>&1 || code=$?
echo "[exit:$code]" >>"$work.log"
$work | ts >>"$work.log" 2>&1 || code=$?
echo "[exit:$code]" | ts >>"$work.log"
[ $code -eq 0 ] || abort "$work failed with exitcode $code"
done
-1
View File
@@ -49,7 +49,6 @@ cat <<EOF
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
System environment....: ${sysconfig_path:-${sysconfig}}
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
Linker................: $LD $LLDP_LDFLAGS $LLDP_BIN_LDFLAGS $LDFLAGS $LIBS
+28
View File
@@ -0,0 +1,28 @@
*~
*.o
gencert
/aclocal.m4
/autom4te.cache/
/aux
/clixon.xml
/compile
/config.h
/config.h.in
/config.guess
/config.log
/config.status
/config.sub
/configure
/depcomp
/install-sh
/libtool
/ltmain.sh
/m4
/missing
GPATH
GRTAGS
GTAGS
Makefile
Makefile.in
+14
View File
@@ -0,0 +1,14 @@
Copyright (c) 2024 The KernelKit Authors
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
+8
View File
@@ -0,0 +1,8 @@
DISTCLEANFILES = *~ *.d
ACLOCAL_AMFLAGS = -I m4
bin_PROGRAMS = gencert
gencert_SOURCES = gencert.c
gencert_CFLAGS = -W -Wall -Wextra -Wno-unused
gencert_CFLAGS = $(ssl_CFLAGS)
gencert_LDADD = $(ssl_LIBS)
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -W portability -vifm
+64
View File
@@ -0,0 +1,64 @@
AC_PREREQ(2.61)
AC_INIT([gencert], [3.0], [https://github.com/kernelkit/infix/issues])
AM_INIT_AUTOMAKE(1.11 foreign)
AM_SILENT_RULES(yes)
AC_CONFIG_FILES([
Makefile
])
AC_PROG_CC
AC_PROG_INSTALL
# Check for pkg-config first, warn if it's not installed
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([ssl], [openssl >= 3.0.0])
test "x$prefix" = xNONE && prefix=$ac_default_prefix
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
DATAROOTDIR=`eval echo $datarootdir`
DATAROOTDIR=`eval echo $DATAROOTDIR`
AC_SUBST(DATAROOTDIR)
LIBDIR=`eval echo $libdir`
LIBDIR=`eval echo $LIBDIR`
AC_SUBST(LIBDIR)
LOCALSTATEDIR=`eval echo $localstatedir`
LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
AC_SUBST(LOCALSTATEDIR)
RUNSTATEDIR=`eval echo $runstatedir`
RUNSTATEDIR=`eval echo $RUNSTATEDIR`
AC_SUBST(RUNSTATEDIR)
SYSCONFDIR=`eval echo $sysconfdir`
SYSCONFDIR=`eval echo $SYSCONFDIR`
AC_SUBST(SYSCONFDIR)
AC_OUTPUT
cat <<EOF
------------------ Summary ------------------
$PACKAGE_NAME version $PACKAGE_VERSION
Prefix................: $prefix
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
System environment....: ${sysconfig_path:-${sysconfig}}
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
Linker................: $LD $LLDP_LDFLAGS $LLDP_BIN_LDFLAGS $LDFLAGS $LIBS
------------- Compiler version --------------
$($CC --version || true)
-------------- Linker version ---------------
$($LD --version || true)
---------------------------------------------
Check the above options and compile with:
${MAKE-make}
EOF
+172
View File
@@ -0,0 +1,172 @@
/* SPDX-License-Identifier: ISC */
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
extern char *__progname;
static int usage(int rc)
{
fprintf(stderr,
"Usage: %s\n"
"\n"
"Options:\n"
" --country COUNTRY Set country, default: US\n"
" --state STATE Set state or province, default: California\n"
" --city CITY Set city name, default: Berkeley\n"
" --organization ORG Set organization name, default: Acme, Inc.\n"
" --organization-unit UNIT Set organization unit name, default: Second\n"
" --common-name CN Set common name, default: none (required!)\n"
" --out-certificate FILE Output certificate\n"
" --out-key FILE Output private key\n"
, __progname);
return rc;
}
int main(int argc, char *argv[])
{
struct option opts[] = {
{"city", required_argument, 0, 'l'},
{"common-name", required_argument, 0, 'n'},
{"country", required_argument, 0, 'c'},
{"help", no_argument, 0, 'h'},
{"organization", required_argument, 0, 'o'},
{"organisation", required_argument, 0, 'o'},
{"organization-unit", required_argument, 0, 'u'},
{"organisation-unit", required_argument, 0, 'u'},
{"out-certificate", required_argument, 0, 'p'},
{"out-key", required_argument, 0, 'k'},
{"state", required_argument, 0, 's'},
{0, 0, 0, 0}
};
char *common_name = NULL, *cert = "certificate.pem", *key = "private.key";
char *country = "US", *state = "California", *locality = "Berkeley";
char *organization = "Acme, Inc.", *unit = "Second";
ASN1_INTEGER *asn1_serno;
EVP_PKEY_CTX *pkey_ctx;
BIGNUM *bn_serial;
X509_NAME *name;
EVP_PKEY *pkey;
X509 *x509;
FILE *fp;
int c;
while ((c = getopt_long(argc, argv, "c:hs:l:o:u:n:", opts, NULL)) != -1) {
switch (c) {
case 'c':
country = optarg;
break;
case 'h':
case '?':
return usage(0);
case 'k':
key = optarg;
break;
case 'l':
locality = optarg;
break;
case 'n':
common_name = optarg;
break;
case 'o':
organization = optarg;
break;
case 'p':
cert = optarg;
break;
case 's':
state = optarg;
break;
case 'u':
unit = optarg;
break;
default:
fprintf(stderr, "got here: '%c'\n", c);
abort();
}
}
if (!common_name)
return usage(1);
OpenSSL_add_all_algorithms();
/* Key generation using EVP */
pkey = EVP_PKEY_new();
pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!EVP_PKEY_keygen_init(pkey_ctx) || !EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, 2048) ||
!EVP_PKEY_keygen(pkey_ctx, &pkey)) {
fprintf(stderr, "Error generating RSA key\n");
EVP_PKEY_CTX_free(pkey_ctx);
return 1;
}
EVP_PKEY_CTX_free(pkey_ctx);
/* Certificate creation */
x509 = X509_new();
assert(x509);
X509_set_version(x509, 2);
/* Generating a random serial number */
bn_serial = BN_new();
assert(bn_serial);
BN_rand(bn_serial, 160, 0, 0); /* Generate a 160-bit serial number */
asn1_serno = BN_to_ASN1_INTEGER(bn_serial, NULL);
assert(asn1_serno);
X509_set_serialNumber(x509, asn1_serno);
ASN1_TIME_set_string(X509_getm_notBefore(x509), "20000101000000Z");
ASN1_TIME_set_string(X509_getm_notAfter(x509), "99990101000000Z");
name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)country, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (unsigned char *)state, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, (unsigned char *)locality, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)organization, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (unsigned char *)unit, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)common_name, -1, -1, 0);
X509_set_issuer_name(x509, name);
X509_set_pubkey(x509, pkey);
if (!X509_sign(x509, pkey, EVP_sha256())) {
fprintf(stderr, "Error signing certificate\n");
return 1;
}
/* Saving the certificate */
fp = fopen(cert, "w");
if (!fp) {
fprintf(stderr, "Failed opening %s for writing: %s\n", cert, strerror(errno));
goto done;
}
PEM_write_X509(fp, x509);
fclose(fp);
/* Saving the private key */
fp = fopen(key, "w");
if (!fp) {
fprintf(stderr, "Failed opening %s for writing: %s\n", key, strerror(errno));
goto done;
}
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
fclose(fp);
done: /* Cleanup */
X509_free(x509);
EVP_PKEY_free(pkey);
BN_free(bn_serial);
ASN1_INTEGER_free(asn1_serno);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
Copyright (c) 2024 The KernelKit Authors
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
+7
View File
@@ -0,0 +1,7 @@
Default Landing Page for Infix
==============================
This is a temporary landing page for the Infix web interface pending the
upcoming RESTCONF based WebUI application.
Use `gen.sh` to update `index.html` from the top-level project README.md

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

+1
View File
@@ -1,4 +1,5 @@
---
- case: meta/reproducible.py
- case: meta/wait.py
- name: Misc tests
+1 -1
View File
@@ -12,7 +12,7 @@ env = infamy.Env()
ctrl = env.ptop.get_ctrl()
infixen = env.ptop.get_infixen()
for ix in infixen:
(_, cport), (_, ixport) = env.ptop.get_path(ctrl, ix)
cport, ixport = env.ptop.get_mgmt_link(ctrl, ix)
print(f"Attaching to {ix}:{ixport} via {ctrl}:{cport}")
exec(f"{ix} = env.attach(\"{ix}\", \"{ixport}\")")
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
import os
import infamy
with infamy.Test() as test:
with test.step("$PYTHONHASHSEED is set"):
seed = os.environ.get("PYTHONHASHSEED")
if seed == None:
print("$PYTHONHASHSEED must be set in order to create a reproducible test environment")
test.fail()
else:
print(f"Specify PYTHONHASHSEED={seed} to reproduce this test environment")
test.succeed()
+6 -6
View File
@@ -8,13 +8,13 @@ import infamy, infamy.neigh
def ll6ping(node):
neigh = None
for (_, cport), (_, nport) in env.ptop.get_paths(ctrl, node):
neigh = infamy.neigh.ll6ping(cport, flags=["-w1", "-c1", "-L", "-n"])
if neigh:
print(f"Found {neigh} on {cport} (connected to {node}:{nport})")
break
cport, nport = env.ptop.get_mgmt_link(ctrl, node)
neigh = infamy.neigh.ll6ping(cport, flags=["-w1", "-c1", "-L", "-n"])
if neigh:
print(f"Found {neigh} on {cport} (connected to {node}:{nport})")
return neigh
return neigh
return None
def netconf_syn(neigh):
try:
+1
View File
@@ -157,6 +157,7 @@ if [ "$containerize" ]; then
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
--device=/dev/net/tun \
--env PYTHONHASHSEED=${PYTHONHASHSEED:-$(shuf -i 0-$(((1 << 32) - 1)) -n 1)} \
--env VIRTUAL_ENV_DISABLE_PROMPT=yes \
--env PROMPT_DIRTRIM="$ixdir" \
--env PS1='\e[1m$(date "+%H:%M:%S") \h\e[0m:\W # ' \
+1 -1
View File
@@ -47,7 +47,7 @@ class Env(object):
if not password:
password = "admin"
ctrl = self.ptop.get_ctrl()
_, cport = self.ptop.get_path(ctrl, (node, port))[0]
cport, _ = self.ptop.get_mgmt_link(ctrl, node)
print(f"Probing {node} on port {cport} for IPv6LL mgmt address ...")
mgmtip = neigh.ll6ping(cport)
+64 -78
View File
@@ -1,88 +1,79 @@
import networkx as nx
from networkx.algorithms import isomorphism
def qstrip(text):
if text.startswith("\"") and text.endswith("\""):
return text[1:-1]
return text
def map_edges(les, pes):
acc = []
les = sorted(list(les.values()), key=lambda x: x.get("kind", ""), reverse=True)
pes = sorted(list(pes.values()), key=lambda x: x.get("kind", ""), reverse=True)
def match_node(n1attrs, n2attrs):
return n1attrs.get("kind") == n2attrs.get("kind")
for i in range(len(les)):
if pes[i].get("kind") != les[i].get("kind"):
return None
def match_edge(e1attrs, e2attrs):
if "kind" in e1attrs or "kind" in e2attrs:
return e1attrs.get("kind") == e2attrs.get("kind")
acc.append((les[i], pes[i]))
return True
return acc
def match_node(pn, ln):
return pn.get("kind") == ln.get("kind")
def match_edge(pes, les):
return map_edges(les, pes) != None
class Topology:
def __init__(self, dotg):
def _qstrip(text):
if text == None:
return None
if text.startswith("\"") and text.endswith("\""):
return text[1:-1]
return text
self.dotg = dotg
edges = {}
self.g = nx.MultiGraph()
for n in self.dotg.get_nodes():
name = n.get_name()
if name in ("node", "edge"):
continue
repr(n.get_attributes())
attrs = { _qstrip(k): _qstrip(v) for k, v in n.get_attributes().items() if k != "label" }
self.g.add_node(name, **attrs)
for e in self.dotg.get_edges():
attrs = e.get_attributes()
if "weight" not in attrs:
attrs["weight"] = 1
edges[tuple(e.get_source().split(":"))] = { tuple(e.get_destination().split(":")): attrs }
sn, sp = e.get_source().split(":")
dn, dp = e.get_destination().split(":")
self.g = nx.Graph(edges, weight=1)
for e in list(self.g.edges):
s, d = e
self.g.nodes[s]["kind"] = "port"
self.g.nodes[d]["kind"] = "port"
sn, sp = s
dn, dp = d
try:
sk = qstrip(self.dotg.get_node(sn)[0].get_attributes()["kind"])
except:
raise ValueError("\"{}\"'s kind is not known".format(sn))
try:
dk = qstrip(self.dotg.get_node(dn)[0].get_attributes()["kind"])
except:
raise ValueError("\"{}\"'s kind is not known".format(dn))
self.g.add_node(sn, kind=sk)
self.g.add_edge(sn, s, weight=0)
self.g.add_node(dn, kind=dk)
self.g.add_edge(dn, d, weight=0)
attrs = { _qstrip(k): _qstrip(v) for k, v in e.get_attributes().items() }
attrs[sn] = sp
attrs[dn] = dp
self.g.add_edge(sn, dn, **attrs)
def map_to(self, phy):
def _map_node(lnode, pnode):
if lnode in self.mapping:
assert(self.mapping[lnode][None] == pnode)
else:
self.mapping[lnode] = { None: pnode }
def _map_port(log, phy):
(lnode, lport) = log
(pnode, pport) = phy
if lport in self.mapping[lnode]:
assert(self.mapping[lnode][lport] == pport)
else:
self.mapping[lnode][lport] = pport
nxmap = isomorphism.GraphMatcher(phy.g, self.g, edge_match=match_edge, node_match=match_node)
if not nxmap.subgraph_is_isomorphic():
mapper = isomorphism.MultiGraphMatcher(phy.g, self.g,
edge_match=match_edge,
node_match=match_node)
if not mapper.subgraph_is_monomorphic():
return False
self.phy = phy
self.mapping = {}
for (phy, log) in nxmap.mapping.items():
if isinstance(log, tuple):
lnode, lport = log
pnode, pport = phy
_map_node(lnode, pnode)
_map_port((lnode, lport), (pnode, pport))
else:
_map_node(log, phy)
for pn, ln in mapper.mapping.items():
self.mapping.setdefault(ln, { None: pn })
for lsrc, ldst in set(self.g.edges()):
psrc = self.mapping[lsrc][None]
pdst = self.mapping[ldst][None]
les = self.g.get_edge_data(lsrc, ldst)
pes = self.phy.g.get_edge_data(psrc, pdst)
for le, pe in map_edges(les, pes):
self.mapping[lsrc][le[lsrc]] = pe[psrc]
self.mapping[ldst][le[ldst]] = pe[pdst]
return True
@@ -116,20 +107,16 @@ class Topology:
password=b.get("password")
return qstrip(password) if password is not None else None
def get_ports(self, node):
ports = self.get_nodes(lambda name, _: name.startswith(f"{node}:"))
return { p.removeprefix(f"{node}:") for p in ports }
def get_link(self, src, dst, flt=lambda _: True):
es = self.g.get_edge_data(src, dst)
for e in es.values():
if flt(e):
return e[src], e[dst]
def get_path(self, src, dst):
path = nx.shortest_path(self.g, src, dst)
return path[1:-1] if path else None
return None
def get_paths(self, src, dst):
paths = nx.all_shortest_paths(self.g, src, dst)
if not paths:
return None
return map(lambda path: path[1:-1], paths)
def get_mgmt_link(self, src, dst):
return self.get_link(src, dst, lambda e: e.get("kind") == "mgmt")
def get_ctrl(self):
ns = self.get_nodes(lambda _, attrs: attrs.get("kind") == "controller")
@@ -139,7 +126,6 @@ class Topology:
def get_infixen(self):
return self.get_nodes(lambda _, attrs: attrs.get("kind") == "infix")
# Support calling this script like so...
#
# python3 topology.py <physical> <logical>