summaryrefslogtreecommitdiff
path: root/scripts/package-build
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/package-build')
-rw-r--r--scripts/package-build/.gitignore (renamed from scripts/package-build/opennhrp/.gitignore)4
-rw-r--r--scripts/package-build/amazon-cloudwatch-agent/.gitignore1
l---------scripts/package-build/amazon-cloudwatch-agent/build.py (renamed from scripts/package-build/opennhrp/build.py)0
-rw-r--r--scripts/package-build/amazon-cloudwatch-agent/package.toml14
-rw-r--r--scripts/package-build/amazon-ssm-agent/.gitignore1
l---------scripts/package-build/amazon-ssm-agent/build.py (renamed from scripts/package-build/pam_tacplus/build.py)0
-rw-r--r--scripts/package-build/amazon-ssm-agent/package.toml16
-rw-r--r--scripts/package-build/aws-gwlbtun/.gitignore9
-rw-r--r--scripts/package-build/bash-completion/.gitignore1
l---------scripts/package-build/bash-completion/build.py1
-rw-r--r--scripts/package-build/bash-completion/package.toml12
-rw-r--r--scripts/package-build/blackbox_exporter/.gitignore1
l---------scripts/package-build/blackbox_exporter/build.py1
-rwxr-xr-xscripts/package-build/blackbox_exporter/build.sh66
-rw-r--r--scripts/package-build/blackbox_exporter/package.toml5
-rwxr-xr-xscripts/package-build/build.py66
-rw-r--r--scripts/package-build/ddclient/.gitignore8
-rw-r--r--scripts/package-build/dropbear/.gitignore8
-rw-r--r--scripts/package-build/dropbear/package.toml4
-rw-r--r--scripts/package-build/dropbear/patches/dropbear/0001-Enable-PAM-support.patch (renamed from scripts/package-build/dropbear/patches/0001-Enable-PAM-support.patch)0
-rw-r--r--scripts/package-build/ethtool/.gitignore8
-rw-r--r--scripts/package-build/ethtool/package.toml2
-rw-r--r--scripts/package-build/frr/.gitignore11
-rw-r--r--scripts/package-build/frr/package.toml13
-rw-r--r--scripts/package-build/frr/patches/frr/0001-Enable-PCRE2-in-Debian-package-builds.patch24
-rw-r--r--scripts/package-build/frr/patches/frr/0001-ldpd-Option-for-disabled-LDP-hello-message-during-TC.patch176
-rw-r--r--scripts/package-build/frr/patches/frr/0003-Clear-Babel-Config-On-Stop.patch29
-rw-r--r--scripts/package-build/frr_exporter/.gitignore1
l---------scripts/package-build/frr_exporter/build.py1
-rw-r--r--scripts/package-build/frr_exporter/package.toml22
-rw-r--r--scripts/package-build/hostap/.gitignore9
-rw-r--r--scripts/package-build/hsflowd/.gitignore7
-rw-r--r--scripts/package-build/hsflowd/package.toml6
-rw-r--r--scripts/package-build/isc-dhcp/.gitignore8
-rw-r--r--scripts/package-build/isc-dhcp/package.toml2
-rw-r--r--scripts/package-build/isc-dhcp/patches/isc-dhcp/0001-Add-support-for-raw-IP-interface-type.patch (renamed from scripts/package-build/isc-dhcp/patches/0001-Add-support-for-raw-IP-interface-type.patch)0
-rw-r--r--scripts/package-build/isc-dhcp/patches/isc-dhcp/0002-Checkpoint-improved-patch.patch (renamed from scripts/package-build/isc-dhcp/patches/0002-Checkpoint-improved-patch.patch)0
-rw-r--r--scripts/package-build/isc-dhcp/patches/isc-dhcp/0003-fix-compilation-errors.patch (renamed from scripts/package-build/isc-dhcp/patches/0003-fix-compilation-errors.patch)0
-rw-r--r--scripts/package-build/isc-dhcp/patches/isc-dhcp/0004-add-support-for-ARPHRD_NONE-interface-type.patch (renamed from scripts/package-build/isc-dhcp/patches/0004-add-support-for-ARPHRD_NONE-interface-type.patch)0
-rw-r--r--scripts/package-build/kea/.gitignore8
-rw-r--r--scripts/package-build/kea/package.toml2
-rw-r--r--scripts/package-build/kea/patches/isc-kea/0001-Add-multithreading-test-mode.patch135
-rw-r--r--scripts/package-build/kea/patches/isc-kea/0002-Add-ping_check-hook-library.patch13277
-rw-r--r--scripts/package-build/keepalived/.gitignore8
-rw-r--r--scripts/package-build/keepalived/package.toml2
-rw-r--r--scripts/package-build/keepalived/patches/0001-vrrp-Set-sysctl-arp_ignore-to-1-on-IPv6-VMACs.patch129
-rw-r--r--scripts/package-build/libnss-mapuser/.gitignore1
l---------scripts/package-build/libnss-mapuser/build.py1
-rw-r--r--scripts/package-build/libnss-mapuser/package.toml9
-rw-r--r--scripts/package-build/libpam-radius-auth/.gitignore1
l---------scripts/package-build/libpam-radius-auth/build.py1
-rw-r--r--scripts/package-build/libpam-radius-auth/package.toml10
-rw-r--r--scripts/package-build/linux-kernel/.gitignore6
-rw-r--r--scripts/package-build/linux-kernel/README.md12
l---------scripts/package-build/linux-kernel/arch1
-rw-r--r--scripts/package-build/linux-kernel/arch/arm64/configs/vyos_defconfig7274
-rw-r--r--scripts/package-build/linux-kernel/arch/x86/configs/vyos_defconfig6396
-rwxr-xr-xscripts/package-build/linux-kernel/build-accel-ppp.sh8
-rwxr-xr-xscripts/package-build/linux-kernel/build-intel-ixgbe.sh107
-rwxr-xr-xscripts/package-build/linux-kernel/build-intel-nic.sh (renamed from scripts/package-build/linux-kernel/build-intel-ixgbevf.sh)76
-rwxr-xr-xscripts/package-build/linux-kernel/build-intel-qat.sh30
-rwxr-xr-xscripts/package-build/linux-kernel/build-ipt-netflow.sh69
-rwxr-xr-xscripts/package-build/linux-kernel/build-jool.py7
-rwxr-xr-xscripts/package-build/linux-kernel/build-kernel.sh54
-rwxr-xr-xscripts/package-build/linux-kernel/build-mellanox-ofed.sh140
-rwxr-xr-xscripts/package-build/linux-kernel/build-nat-rtsp.sh12
-rwxr-xr-xscripts/package-build/linux-kernel/build-openvpn-dco.sh8
-rwxr-xr-xscripts/package-build/linux-kernel/build-realtek-r8152.py95
-rwxr-xr-xscripts/package-build/linux-kernel/build.py74
-rw-r--r--scripts/package-build/linux-kernel/package.toml33
l---------scripts/package-build/linux-kernel/patches1
-rw-r--r--scripts/package-build/linux-kernel/patches/accel-ppp/0001-L2TP-Include-Calling-Number-to-Calling-Station-ID-RA.patch183
-rw-r--r--scripts/package-build/linux-kernel/patches/accel-ppp/0002-Radius-Dns-Server-IPv6-Address.patch195
-rw-r--r--scripts/package-build/linux-kernel/patches/ixgbe/0001-ixgbe-always-enable-support-for-unsupported-SFP-modu.patch48
-rw-r--r--scripts/package-build/linux-kernel/patches/ixgbe/0002-BACKPORT-linux-v6.9-PATCH-ixgbe-Add-1000BASE-BX-supp.patch259
-rw-r--r--scripts/package-build/linux-kernel/patches/kernel/0001-linkstate-ip-device-attribute.patch158
-rw-r--r--scripts/package-build/linux-kernel/patches/kernel/0002-inotify-support-for-stackable-filesystems.patch298
-rwxr-xr-xscripts/package-build/linux-kernel/sign-modules.sh15
-rw-r--r--scripts/package-build/ndppd/.gitignore8
-rw-r--r--scripts/package-build/ndppd/patches/ndppd/0001-skip-route-table-if-there-is-no-auto-rule.patch (renamed from scripts/package-build/ndppd/patches/0001-skip-route-table-if-there-is-no-auto-rule.patch)0
-rw-r--r--scripts/package-build/ndppd/patches/ndppd/0002-set-vyos-version.patch (renamed from scripts/package-build/ndppd/patches/0002-set-vyos-version.patch)0
-rw-r--r--scripts/package-build/net-snmp/.gitignore7
-rw-r--r--scripts/package-build/net-snmp/patches/net-snmp/add-linux-6.7-compatibility-parsing.patch (renamed from scripts/package-build/net-snmp/patches/add-linux-6.7-compatibility-parsing.patch)0
-rw-r--r--scripts/package-build/netfilter/.gitignore6
l---------[-rwxr-xr-x]scripts/package-build/netfilter/build.py190
-rw-r--r--scripts/package-build/node_exporter/.gitignore1
l---------scripts/package-build/node_exporter/build.py1
-rw-r--r--scripts/package-build/node_exporter/package.toml21
-rw-r--r--scripts/package-build/opennhrp/package.toml21
-rw-r--r--scripts/package-build/openvpn-otp/.gitignore7
-rw-r--r--scripts/package-build/openvpn-otp/package.toml2
-rw-r--r--scripts/package-build/owamp/.gitignore7
-rw-r--r--scripts/package-build/pam_tacplus/.gitignore7
-rw-r--r--scripts/package-build/pam_tacplus/package.toml19
-rw-r--r--scripts/package-build/pmacct/.gitignore7
-rw-r--r--scripts/package-build/pmacct/patches/pmacct/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch (renamed from scripts/package-build/pmacct/patches/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch)0
-rw-r--r--scripts/package-build/podman/.gitignore8
-rw-r--r--scripts/package-build/podman/package.toml2
-rw-r--r--scripts/package-build/pyhumps/.gitignore8
-rw-r--r--scripts/package-build/radvd/.gitignore7
-rw-r--r--scripts/package-build/radvd/package.toml2
-rw-r--r--scripts/package-build/strongswan/.gitignore7
-rwxr-xr-xscripts/package-build/strongswan/build-vici.sh21
-rw-r--r--scripts/package-build/strongswan/package.toml2
-rw-r--r--scripts/package-build/strongswan/patches/strongswan/0001-charon-add-optional-source-and-remote-overrides-for-.patch (renamed from scripts/package-build/strongswan/patches/0001-charon-add-optional-source-and-remote-overrides-for-.patch)0
-rw-r--r--scripts/package-build/strongswan/patches/strongswan/0002-vici-send-certificates-for-ike-sa-events.patch (renamed from scripts/package-build/strongswan/patches/0002-vici-send-certificates-for-ike-sa-events.patch)0
-rw-r--r--scripts/package-build/strongswan/patches/strongswan/0003-vici-add-support-for-individual-sa-state-changes.patch (renamed from scripts/package-build/strongswan/patches/0003-vici-add-support-for-individual-sa-state-changes.patch)0
-rw-r--r--scripts/package-build/strongswan/patches/strongswan/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch (renamed from scripts/package-build/strongswan/patches/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch)0
-rw-r--r--scripts/package-build/tacacs/.gitignore3
l---------scripts/package-build/tacacs/build.py1
-rw-r--r--scripts/package-build/tacacs/package.toml24
-rw-r--r--scripts/package-build/telegraf/.gitignore7
-rw-r--r--scripts/package-build/vpp/.gitignore2
l---------scripts/package-build/vpp/build.py1
-rw-r--r--scripts/package-build/vpp/package.toml35
-rw-r--r--scripts/package-build/vyos-1x/.gitignore2
l---------scripts/package-build/vyos-1x/build.py1
-rw-r--r--scripts/package-build/vyos-1x/package.toml11
-rw-r--r--scripts/package-build/waagent/.gitignore9
-rw-r--r--scripts/package-build/waagent/package.toml2
-rw-r--r--scripts/package-build/wide-dhcpv6/.gitignore8
-rw-r--r--scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0023-dhcpc6-support-per-interface-client-DUIDs.patch (renamed from scripts/package-build/wide-dhcpv6/patches/0023-dhcpc6-support-per-interface-client-DUIDs.patch)0
-rw-r--r--scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0024-bind-to-single-socket.patch (renamed from scripts/package-build/wide-dhcpv6/patches/0024-bind-to-single-socket.patch)0
-rw-r--r--scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0025-option-to-prevent-ia-release.patch (renamed from scripts/package-build/wide-dhcpv6/patches/0025-option-to-prevent-ia-release.patch)0
-rw-r--r--scripts/package-build/xen-guest-agent/.gitignore1
l---------scripts/package-build/xen-guest-agent/build.py1
-rw-r--r--scripts/package-build/xen-guest-agent/package.toml34
127 files changed, 29406 insertions, 777 deletions
diff --git a/scripts/package-build/opennhrp/.gitignore b/scripts/package-build/.gitignore
index 65d0752b..a1b8b226 100644
--- a/scripts/package-build/opennhrp/.gitignore
+++ b/scripts/package-build/.gitignore
@@ -1,6 +1,8 @@
-opennhrp/
*.buildinfo
*.build
*.changes
*.deb
+*.udeb
*.dsc
+*.tar.gz
+*.tar.xz
diff --git a/scripts/package-build/amazon-cloudwatch-agent/.gitignore b/scripts/package-build/amazon-cloudwatch-agent/.gitignore
new file mode 100644
index 00000000..5eb3e42a
--- /dev/null
+++ b/scripts/package-build/amazon-cloudwatch-agent/.gitignore
@@ -0,0 +1 @@
+/amazon-cloudwatch-agent/
diff --git a/scripts/package-build/opennhrp/build.py b/scripts/package-build/amazon-cloudwatch-agent/build.py
index 3c76af73..3c76af73 120000
--- a/scripts/package-build/opennhrp/build.py
+++ b/scripts/package-build/amazon-cloudwatch-agent/build.py
diff --git a/scripts/package-build/amazon-cloudwatch-agent/package.toml b/scripts/package-build/amazon-cloudwatch-agent/package.toml
new file mode 100644
index 00000000..120a17f9
--- /dev/null
+++ b/scripts/package-build/amazon-cloudwatch-agent/package.toml
@@ -0,0 +1,14 @@
+[[packages]]
+name = "amazon-cloudwatch-agent"
+commit_id = "v1.300050.0"
+scm_url = "https://github.com/aws/amazon-cloudwatch-agent"
+
+build_cmd = """
+
+make clean test check_secrets amazon-cloudwatch-agent-linux package-deb
+ARCH=$(dpkg --print-architecture)
+TAG=$(git describe --tags --abbrev=0)
+COMMIT=$(git rev-parse --short HEAD)
+cp ./build/bin/linux/${ARCH}/*.deb ../amazon-cloudwatch-agent_${TAG}_${COMMIT}_${ARCH}.deb
+
+"""
diff --git a/scripts/package-build/amazon-ssm-agent/.gitignore b/scripts/package-build/amazon-ssm-agent/.gitignore
new file mode 100644
index 00000000..78fa9ab9
--- /dev/null
+++ b/scripts/package-build/amazon-ssm-agent/.gitignore
@@ -0,0 +1 @@
+/amazon-ssm-agent/
diff --git a/scripts/package-build/pam_tacplus/build.py b/scripts/package-build/amazon-ssm-agent/build.py
index 3c76af73..3c76af73 120000
--- a/scripts/package-build/pam_tacplus/build.py
+++ b/scripts/package-build/amazon-ssm-agent/build.py
diff --git a/scripts/package-build/amazon-ssm-agent/package.toml b/scripts/package-build/amazon-ssm-agent/package.toml
new file mode 100644
index 00000000..ecd2fdf6
--- /dev/null
+++ b/scripts/package-build/amazon-ssm-agent/package.toml
@@ -0,0 +1,16 @@
+[[packages]]
+name = "amazon-ssm-agent"
+commit_id = "3.3.1311.0"
+scm_url = "https://github.com/aws/amazon-ssm-agent"
+
+build_cmd = """
+
+ARCH=$(dpkg --print-architecture)
+TAG=$(git describe --tags --abbrev=0)
+COMMIT=$(git rev-parse --short HEAD)
+
+make build-linux
+make package-deb
+cp ./bin/debian_${ARCH}/*.deb ../amazon-ssm-agent_${TAG}_${COMMIT}_${ARCH}.deb
+
+"""
diff --git a/scripts/package-build/aws-gwlbtun/.gitignore b/scripts/package-build/aws-gwlbtun/.gitignore
index 0fe7946f..dab49f62 100644
--- a/scripts/package-build/aws-gwlbtun/.gitignore
+++ b/scripts/package-build/aws-gwlbtun/.gitignore
@@ -1,8 +1 @@
-aws-gwlbtun*/
-*.tar.gz
-*.tar.xz
-*.deb
-*.dsc
-*.buildinfo
-*.build
-*.changes \ No newline at end of file
+/aws-gwlbtun*/
diff --git a/scripts/package-build/bash-completion/.gitignore b/scripts/package-build/bash-completion/.gitignore
new file mode 100644
index 00000000..73e9d517
--- /dev/null
+++ b/scripts/package-build/bash-completion/.gitignore
@@ -0,0 +1 @@
+/bash-completion/
diff --git a/scripts/package-build/bash-completion/build.py b/scripts/package-build/bash-completion/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/bash-completion/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/bash-completion/package.toml b/scripts/package-build/bash-completion/package.toml
new file mode 100644
index 00000000..49667429
--- /dev/null
+++ b/scripts/package-build/bash-completion/package.toml
@@ -0,0 +1,12 @@
+# VyOS CLI requires an older version of bash-completion to work
+
+[[packages]]
+name = "bash-completion"
+commit_id = "debian/2.8-6"
+scm_url = "https://salsa.debian.org/debian/bash-completion"
+
+build_cmd = """
+
+# Build deb
+dpkg-buildpackage -b -us -uc
+"""
diff --git a/scripts/package-build/blackbox_exporter/.gitignore b/scripts/package-build/blackbox_exporter/.gitignore
new file mode 100644
index 00000000..435e791f
--- /dev/null
+++ b/scripts/package-build/blackbox_exporter/.gitignore
@@ -0,0 +1 @@
+/blackbox_exporter/
diff --git a/scripts/package-build/blackbox_exporter/build.py b/scripts/package-build/blackbox_exporter/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/blackbox_exporter/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/blackbox_exporter/build.sh b/scripts/package-build/blackbox_exporter/build.sh
new file mode 100755
index 00000000..127c03be
--- /dev/null
+++ b/scripts/package-build/blackbox_exporter/build.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+CWD=$(pwd)
+set -e
+
+BUILD_ARCH=$(dpkg-architecture -qDEB_TARGET_ARCH)
+
+SRC="blackbox_exporter"
+if [ ! -d ${SRC} ]; then
+ echo "Source directory does not exist, please 'git clone'"
+ exit 1
+fi
+
+cd $SRC
+
+mkdir -p debian
+
+echo "I: Create $SRC/debian/control"
+cat <<EOF > debian/control
+Source: blackbox-exporter
+Section: net
+Priority: optional
+Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
+Build-Depends: debhelper-compat (= 13)
+Standards-Version: 4.5.1
+Homepage: https://github.com/prometheus/blackbox_exporter
+
+Package: blackbox-exporter
+Architecture: ${BUILD_ARCH}
+Depends: \${shlibs:Depends}, \${misc:Depends}
+Description: The blackbox exporter allows blackbox probing of endpoints over HTTP, HTTPS, DNS, TCP, ICMP and gRPC.
+EOF
+
+echo "I: Create $SRC/debian/changelog"
+cat <<EOF > debian/changelog
+blackbox-exporter (0.26.0) UNRELEASED; urgency=medium
+
+ * Upstream package
+
+ -- VyOS Maintainers <maintainers@vyos.io> Thu, 26 Sep 2024 12:35:47 +0000
+EOF
+
+echo "I: Create $SRC/debian/rules"
+cat <<EOF > debian/rules
+#!/usr/bin/make -f
+
+clean:
+ @# Do nothing
+
+build:
+ @# Do nothing
+
+binary:
+ mkdir -p debian/blackbox-exporter
+ mkdir -p debian/blackbox-exporter/usr/sbin
+ mkdir -p debian/blackbox-exporter/run/blackbox_exporter
+ cp blackbox_exporter debian/blackbox-exporter/usr/sbin/blackbox_exporter
+ dh_gencontrol
+ dh_builddeb
+EOF
+chmod +x debian/rules
+
+echo "I: Build blackbox_exporter"
+go build
+
+echo "I: Build Debian Package"
+dpkg-buildpackage -uc -us -tc -b -d
diff --git a/scripts/package-build/blackbox_exporter/package.toml b/scripts/package-build/blackbox_exporter/package.toml
new file mode 100644
index 00000000..a59a3fdd
--- /dev/null
+++ b/scripts/package-build/blackbox_exporter/package.toml
@@ -0,0 +1,5 @@
+[[packages]]
+name = "blackbox_exporter"
+commit_id = "v0.26.0"
+scm_url = "https://github.com/prometheus/blackbox_exporter"
+build_cmd = "cd ..; y | ./build.sh"
diff --git a/scripts/package-build/build.py b/scripts/package-build/build.py
index 99180e17..9c1df7b3 100755
--- a/scripts/package-build/build.py
+++ b/scripts/package-build/build.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright (C) 2024-2025 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -58,7 +58,6 @@ def apply_patches(repo_dir: Path, patch_dir: Path) -> None:
series.write(patch.name + '\n')
print(f"I: Applied patch: {patch.name}")
-
def prepare_package(repo_dir: Path, install_data: str) -> None:
"""Prepare a package"""
if not install_data:
@@ -75,12 +74,11 @@ def prepare_package(repo_dir: Path, install_data: str) -> None:
raise
-def build_package(package: list, dependencies: list, patch_dir: Path) -> None:
+def build_package(package: list, patch_dir: Path) -> None:
"""Build a package from the repository
Args:
package (list): List of Packages from toml
- dependencies (list): List of additional dependencies
patch_dir (Path): Directory containing patches
"""
repo_name = package['name']
@@ -94,12 +92,51 @@ def build_package(package: list, dependencies: list, patch_dir: Path) -> None:
# Check out the specific commit
run(['git', 'checkout', package['commit_id']], cwd=repo_dir, check=True)
- # Ensure dependencies
- ensure_dependencies(dependencies)
-
- # Apply patches if any
- if (repo_dir / 'patches'):
- apply_patches(repo_dir, patch_dir)
+ # The `pre_build_hook` is an optional configuration defined in `package.toml`.
+ # It executes after the repository is checked out and before the build process begins.
+ # This hook allows you to perform preparatory tasks, such as creating directories,
+ # copying files, or running custom scripts/commands.
+ #
+ # Usage:
+ # - Single command:
+ # pre_build_hook = "echo 'Hello Pre-Build-Hook'"
+ #
+ # - Multi-line commands:
+ # pre_build_hook = """
+ # mkdir -p ../hello/vyos
+ # mkdir -p ../vyos
+ # cp example.txt ../vyos
+ # """
+ #
+ # - Combination of commands and scripts:
+ # pre_build_hook = "ls -l; ./script.sh"
+ pre_build_hook = package.get('pre_build_hook', '')
+ if pre_build_hook:
+ try:
+ print(f'I: execute pre_build_hook for the package "{repo_name}"')
+ run(pre_build_hook, cwd=repo_dir, check=True, shell=True)
+ except CalledProcessError as e:
+ print(e)
+ print(f"I: pre_build_hook failed for the {repo_name}")
+ raise
+
+ # Apply patches if the 'apply_patches' key is set to True (default) in the package configuration
+ # This allows skipping patch application for specific packages when desired
+ #
+ # Usage:
+ # apply_patches = false
+ #
+ # Default to True if the key is missing
+ if package.get('apply_patches', True):
+ # Check if the 'patches' directory exists in the repository
+ if (repo_dir / 'patches'):
+ apply_patches(repo_dir, patch_dir / repo_name)
+
+ # Sanitize the commit ID and build a tarball for the package
+ commit_id_sanitized = package['commit_id'].replace('/', '_')
+ tarball_name = f"{repo_name}_{commit_id_sanitized}.tar.gz"
+ run(['tar', '-czf', tarball_name, '-C', str(repo_dir.parent), repo_name], check=True)
+ print(f"I: Tarball created: {tarball_name}")
# Prepare the package if required
if package.get('prepare_package', False):
@@ -171,11 +208,14 @@ if __name__ == '__main__':
packages = config['packages']
patch_dir = Path(args.patch_dir)
- for package in packages:
- dependencies = package.get('dependencies', {}).get('packages', [])
+ # Load global dependencies
+ global_dependencies = config.get('dependencies', {}).get('packages', [])
+ if global_dependencies:
+ ensure_dependencies(global_dependencies)
+ for package in packages:
# Build the package
- build_package(package, dependencies, patch_dir)
+ build_package(package, patch_dir)
# Clean up build dependency packages after build
cleanup_build_deps(Path(package['name']))
diff --git a/scripts/package-build/ddclient/.gitignore b/scripts/package-build/ddclient/.gitignore
index aeb8af66..17d0b753 100644
--- a/scripts/package-build/ddclient/.gitignore
+++ b/scripts/package-build/ddclient/.gitignore
@@ -1,7 +1 @@
-ddclient/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/ddclient/
diff --git a/scripts/package-build/dropbear/.gitignore b/scripts/package-build/dropbear/.gitignore
index 6e8cff9c..58c2ff3d 100644
--- a/scripts/package-build/dropbear/.gitignore
+++ b/scripts/package-build/dropbear/.gitignore
@@ -1,7 +1 @@
-dropbear/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/dropbear/
diff --git a/scripts/package-build/dropbear/package.toml b/scripts/package-build/dropbear/package.toml
index cbb885ee..a00aad3d 100644
--- a/scripts/package-build/dropbear/package.toml
+++ b/scripts/package-build/dropbear/package.toml
@@ -3,5 +3,5 @@ name = "dropbear"
commit_id = "debian/2022.83-1+deb12u1"
scm_url = "https://salsa.debian.org/debian/dropbear.git"
-[packages.dependencies]
-packages = ["libpam0g-dev"] \ No newline at end of file
+[dependencies]
+packages = ["libpam0g-dev"]
diff --git a/scripts/package-build/dropbear/patches/0001-Enable-PAM-support.patch b/scripts/package-build/dropbear/patches/dropbear/0001-Enable-PAM-support.patch
index fa6cf620..fa6cf620 100644
--- a/scripts/package-build/dropbear/patches/0001-Enable-PAM-support.patch
+++ b/scripts/package-build/dropbear/patches/dropbear/0001-Enable-PAM-support.patch
diff --git a/scripts/package-build/ethtool/.gitignore b/scripts/package-build/ethtool/.gitignore
index f964bd07..16adf9e5 100644
--- a/scripts/package-build/ethtool/.gitignore
+++ b/scripts/package-build/ethtool/.gitignore
@@ -1,7 +1 @@
-ethtool/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/ethtool/
diff --git a/scripts/package-build/ethtool/package.toml b/scripts/package-build/ethtool/package.toml
index 9468ed82..ec22a06c 100644
--- a/scripts/package-build/ethtool/package.toml
+++ b/scripts/package-build/ethtool/package.toml
@@ -1,4 +1,4 @@
[[packages]]
name = "ethtool"
-commit_id = "debian/1%6.6-1"
+commit_id = "debian/1%6.10-1"
scm_url = "https://salsa.debian.org/kernel-team/ethtool"
diff --git a/scripts/package-build/frr/.gitignore b/scripts/package-build/frr/.gitignore
index 590895c0..93dfaca8 100644
--- a/scripts/package-build/frr/.gitignore
+++ b/scripts/package-build/frr/.gitignore
@@ -1,8 +1,3 @@
-frr/
-rtrlib/
-libyang/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/frr/
+/rtrlib/
+/libyang/
diff --git a/scripts/package-build/frr/package.toml b/scripts/package-build/frr/package.toml
index 48d51ae6..8ff35777 100644
--- a/scripts/package-build/frr/package.toml
+++ b/scripts/package-build/frr/package.toml
@@ -1,6 +1,6 @@
[[packages]]
name = "libyang"
-commit_id = "v2.1.148"
+commit_id = "v3.4.2"
scm_url = "https://github.com/CESNET/libyang.git"
build_cmd = "pipx run apkg build -i && find pkg/pkgs -type f -name *.deb -exec mv -t .. {} +"
@@ -8,20 +8,20 @@ build_cmd = "pipx run apkg build -i && find pkg/pkgs -type f -name *.deb -exec m
name = "rtrlib"
commit_id = "v0.8.0"
scm_url = "https://github.com/rtrlib/rtrlib.git"
-build_cmd = "sudo mk-build-deps --install --tool 'apt-get --yes --no-install-recommends'; dpkg-buildpackage -uc -us -tc -b"
[[packages]]
name = "frr"
-commit_id = "stable/9.1"
+commit_id = "stable/10.2"
scm_url = "https://github.com/FRRouting/frr.git"
-build_cmd = "sudo dpkg -i ../*.deb; sudo dpkg-buildpackage -us -uc -tc -b -Ppkg.frr.rtrlib,pkg.frr.lua"
+build_cmd = "sudo dpkg -i ../*.deb; dpkg-buildpackage -us -uc -tc -b -Ppkg.frr.rtrlib,pkg.frr.lua"
-[packages.dependencies]
+[dependencies]
packages = [
"chrpath",
"gawk",
"install-info",
"libcap-dev",
+ "libc-ares-dev",
"libjson-c-dev",
"librtr-dev",
"libpam-dev",
@@ -32,5 +32,6 @@ packages = [
"protobuf-c-compiler",
"python3-dev:native",
"texinfo",
- "lua5.3"
+ "lua5.3",
+ "doxygen"
]
diff --git a/scripts/package-build/frr/patches/frr/0001-Enable-PCRE2-in-Debian-package-builds.patch b/scripts/package-build/frr/patches/frr/0001-Enable-PCRE2-in-Debian-package-builds.patch
new file mode 100644
index 00000000..545e7d5e
--- /dev/null
+++ b/scripts/package-build/frr/patches/frr/0001-Enable-PCRE2-in-Debian-package-builds.patch
@@ -0,0 +1,24 @@
+From 21800432167ac022c01772df993efca8d4969b38 Mon Sep 17 00:00:00 2001
+From: Daniil Baturin <daniil@baturin.org>
+Date: Wed, 6 Nov 2024 15:58:10 +0000
+Subject: [PATCH] Enable PCRE2 in Debian package builds
+
+---
+ debian/rules | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/debian/rules b/debian/rules
+index 43e5d7e61..1f971ab22 100755
+--- a/debian/rules
++++ b/debian/rules
+@@ -69,6 +69,7 @@ override_dh_auto_configure:
+ --enable-vty-group=frrvty \
+ --enable-configfile-mask=0640 \
+ --enable-logfile-mask=0640 \
++ --enable-pcre2posix \
+ # end
+
+ override_dh_auto_install:
+--
+2.47.0
+
diff --git a/scripts/package-build/frr/patches/frr/0001-ldpd-Option-for-disabled-LDP-hello-message-during-TC.patch b/scripts/package-build/frr/patches/frr/0001-ldpd-Option-for-disabled-LDP-hello-message-during-TC.patch
new file mode 100644
index 00000000..67f85d01
--- /dev/null
+++ b/scripts/package-build/frr/patches/frr/0001-ldpd-Option-for-disabled-LDP-hello-message-during-TC.patch
@@ -0,0 +1,176 @@
+From 945eff42df61982585011fa8427050c74ca90c6b Mon Sep 17 00:00:00 2001
+From: Andrii Melnychenko <a.melnychenko@vyos.io>
+Date: Mon, 17 Mar 2025 13:25:20 +0100
+Subject: [PATCH 1/1] ldpd: Option for disabled LDP hello message during TCP
+
+Added option "disable-establish-hello" that disableds
+sending additional LDP hello multicast messages during
+TCP session establishment.
+This option enables per interface: "(config-ldp-af-if)".
+
+Signed-off-by: Andrii Melnychenko <a.melnychenko@vyos.io>
+---
+ ldpd/interface.c | 2 ++
+ ldpd/ldp_vty.h | 1 +
+ ldpd/ldp_vty_cmds.c | 11 +++++++++++
+ ldpd/ldp_vty_conf.c | 32 ++++++++++++++++++++++++++++++++
+ ldpd/ldpd.c | 1 +
+ ldpd/ldpd.h | 1 +
+ ldpd/neighbor.c | 5 +++--
+ 7 files changed, 51 insertions(+), 2 deletions(-)
+
+diff --git a/ldpd/interface.c b/ldpd/interface.c
+index f0e70cbac..6fccd4af5 100644
+--- a/ldpd/interface.c
++++ b/ldpd/interface.c
+@@ -63,11 +63,13 @@ if_new(const char *name)
+ iface->ipv4.af = AF_INET;
+ iface->ipv4.iface = iface;
+ iface->ipv4.enabled = 0;
++ iface->ipv4.disable_establish_hello = 0;
+
+ /* ipv6 */
+ iface->ipv6.af = AF_INET6;
+ iface->ipv6.iface = iface;
+ iface->ipv6.enabled = 0;
++ iface->ipv6.disable_establish_hello = 0;
+
+ return (iface);
+ }
+diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h
+index 5c83d1c56..196d05c93 100644
+--- a/ldpd/ldp_vty.h
++++ b/ldpd/ldp_vty.h
+@@ -24,6 +24,7 @@ int ldp_vty_allow_broken_lsp(struct vty *, const char *);
+ int ldp_vty_address_family (struct vty *, const char *, const char *);
+ int ldp_vty_disc_holdtime(struct vty *, const char *, enum hello_type, long);
+ int ldp_vty_disc_interval(struct vty *, const char *, enum hello_type, long);
++int ldp_vty_disable_establish_hello(struct vty *, const char *);
+ int ldp_vty_targeted_hello_accept(struct vty *, const char *, const char *);
+ int ldp_vty_nbr_session_holdtime(struct vty *, const char *, struct in_addr, long);
+ int ldp_vty_af_session_holdtime(struct vty *, const char *, long);
+diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
+index e046ae996..d6c36c35b 100644
+--- a/ldpd/ldp_vty_cmds.c
++++ b/ldpd/ldp_vty_cmds.c
+@@ -122,6 +122,15 @@ DEFPY (ldp_discovery_link_interval,
+ return (ldp_vty_disc_interval(vty, no, HELLO_LINK, interval));
+ }
+
++DEFPY (ldp_disable_establish_hello,
++ ldp_disable_establish_hello_cmd,
++ "[no] disable-establish-hello",
++ NO_STR
++ "Disable sending additional LDP hello message on establishing LDP tcp connection\n")
++{
++ return ldp_vty_disable_establish_hello(vty, no);
++}
++
+ DEFPY (ldp_discovery_targeted_interval,
+ ldp_discovery_targeted_interval_cmd,
+ "[no] discovery targeted-hello interval (1-65535)$interval",
+@@ -866,9 +875,11 @@ ldp_vty_init (void)
+
+ install_element(LDP_IPV4_IFACE_NODE, &ldp_discovery_link_holdtime_cmd);
+ install_element(LDP_IPV4_IFACE_NODE, &ldp_discovery_link_interval_cmd);
++ install_element(LDP_IPV4_IFACE_NODE, &ldp_disable_establish_hello_cmd);
+
+ install_element(LDP_IPV6_IFACE_NODE, &ldp_discovery_link_holdtime_cmd);
+ install_element(LDP_IPV6_IFACE_NODE, &ldp_discovery_link_interval_cmd);
++ install_element(LDP_IPV6_IFACE_NODE, &ldp_disable_establish_hello_cmd);
+
+ install_element(LDP_L2VPN_NODE, &ldp_bridge_cmd);
+ install_element(LDP_L2VPN_NODE, &ldp_mtu_cmd);
+diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
+index ffff67683..56ad071c8 100644
+--- a/ldpd/ldp_vty_conf.c
++++ b/ldpd/ldp_vty_conf.c
+@@ -119,6 +119,8 @@ ldp_af_iface_config_write(struct vty *vty, int af)
+ ia->hello_interval != 0)
+ vty_out (vty, " discovery hello interval %u\n",
+ ia->hello_interval);
++ if (ia->disable_establish_hello)
++ vty_out (vty, " disable-establish-hello\n");
+
+ vty_out (vty, " exit\n");
+ }
+@@ -632,6 +634,36 @@ ldp_vty_disc_interval(struct vty *vty, const char *negate,
+ return (CMD_SUCCESS);
+ }
+
++int
++ldp_vty_disable_establish_hello(struct vty *vty,
++ const char *negate)
++{
++ struct iface *iface;
++ struct iface_af *ia;
++ int af;
++
++ switch (vty->node) {
++ case LDP_IPV4_IFACE_NODE:
++ case LDP_IPV6_IFACE_NODE:
++ af = ldp_vty_get_af(vty);
++ iface = VTY_GET_CONTEXT(iface);
++ VTY_CHECK_CONTEXT(iface);
++
++ ia = iface_af_get(iface, af);
++ if (negate)
++ ia->disable_establish_hello = 0;
++ else
++ ia->disable_establish_hello = 1;
++
++ ldp_config_apply(vty, vty_conf);
++ break;
++ default:
++ fatalx("ldp_vty_disable_establish_hello: unexpected node");
++ }
++
++ return (CMD_SUCCESS);
++}
++
+ int
+ ldp_vty_targeted_hello_accept(struct vty *vty, const char *negate,
+ const char *acl_from_str)
+diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
+index 4d38fdcd0..9a5667c26 100644
+--- a/ldpd/ldpd.c
++++ b/ldpd/ldpd.c
+@@ -1604,6 +1604,7 @@ merge_iface_af(struct iface_af *ia, struct iface_af *xi)
+ }
+ ia->hello_holdtime = xi->hello_holdtime;
+ ia->hello_interval = xi->hello_interval;
++ ia->disable_establish_hello = xi->disable_establish_hello;
+ }
+
+ static void
+diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
+index ad831a6ea..40a1e8c3c 100644
+--- a/ldpd/ldpd.h
++++ b/ldpd/ldpd.h
+@@ -332,6 +332,7 @@ struct iface_af {
+ struct event *hello_timer;
+ uint16_t hello_holdtime;
+ uint16_t hello_interval;
++ int disable_establish_hello;
+ };
+
+ struct iface_ldp_sync {
+diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
+index 2596c7948..00a809186 100644
+--- a/ldpd/neighbor.c
++++ b/ldpd/neighbor.c
+@@ -630,8 +630,9 @@ nbr_establish_connection(struct nbr *nbr)
+ * an adjacency as well.
+ */
+ RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree)
+- send_hello(adj->source.type, adj->source.link.ia,
+- adj->source.target);
++ if (!(adj->source.type == HELLO_LINK && adj->source.link.ia->disable_establish_hello))
++ send_hello(adj->source.type, adj->source.link.ia,
++ adj->source.target);
+
+ if (connect(nbr->fd, &remote_su.sa, sockaddr_len(&remote_su.sa)) == -1) {
+ if (errno == EINPROGRESS) {
+--
+2.43.0
+
diff --git a/scripts/package-build/frr/patches/frr/0003-Clear-Babel-Config-On-Stop.patch b/scripts/package-build/frr/patches/frr/0003-Clear-Babel-Config-On-Stop.patch
new file mode 100644
index 00000000..fea45891
--- /dev/null
+++ b/scripts/package-build/frr/patches/frr/0003-Clear-Babel-Config-On-Stop.patch
@@ -0,0 +1,29 @@
+From c3c70e87b040233263b9594d14582dfedfecc92e Mon Sep 17 00:00:00 2001
+From: Yaroslav Kholod <y.kholod@vyos.io>
+Date: Wed, 18 Dec 2024 11:48:29 +0200
+Subject: [PATCH] #17413: Clean babeld config on stop
+
+---
+ babeld/babeld.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/babeld/babeld.c b/babeld/babeld.c
+index b562f0b70..6f1a9a3d7 100644
+--- a/babeld/babeld.c
++++ b/babeld/babeld.c
+@@ -304,6 +304,12 @@ void babel_clean_routing_process(void)
+ flush_all_routes();
+ babel_interface_close_all();
+
++ /* Clean babel config */
++ diversity_kind = DIVERSITY_NONE;
++ diversity_factor = BABEL_DEFAULT_DIVERSITY_FACTOR;
++ resend_delay = BABEL_DEFAULT_RESEND_DELAY;
++ smoothing_half_life = BABEL_DEFAULT_SMOOTHING_HALF_LIFE;
++
+ /* cancel events */
+ event_cancel(&babel_routing_process->t_read);
+ event_cancel(&babel_routing_process->t_update);
+--
+2.43.0
+
diff --git a/scripts/package-build/frr_exporter/.gitignore b/scripts/package-build/frr_exporter/.gitignore
new file mode 100644
index 00000000..aee4cba5
--- /dev/null
+++ b/scripts/package-build/frr_exporter/.gitignore
@@ -0,0 +1 @@
+/frr_exporter/
diff --git a/scripts/package-build/frr_exporter/build.py b/scripts/package-build/frr_exporter/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/frr_exporter/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/frr_exporter/package.toml b/scripts/package-build/frr_exporter/package.toml
new file mode 100644
index 00000000..607c4c68
--- /dev/null
+++ b/scripts/package-build/frr_exporter/package.toml
@@ -0,0 +1,22 @@
+[[packages]]
+name = "frr_exporter"
+commit_id = "v1.5.0"
+scm_url = "https://github.com/tynany/frr_exporter"
+
+build_cmd = """
+
+# Create the install directory
+mkdir -p debian/usr/sbin
+make setup_promu
+go build
+
+# Move the frr_exporter binary to the install directory
+mv frr_exporter debian/usr/sbin
+
+# Build the Debian package
+fpm --input-type dir --output-type deb --name frr-exporter \
+ --version $(git describe --tags --always | cut -c2-) --deb-compression gz \
+ --maintainer "VyOS Package Maintainers <maintainers@vyos.net>" \
+ --description "Prometheus exporter for FRR" \
+ --license Apache-2.0 -C debian --package ..
+"""
diff --git a/scripts/package-build/hostap/.gitignore b/scripts/package-build/hostap/.gitignore
index f9c7eb32..1a2c97d8 100644
--- a/scripts/package-build/hostap/.gitignore
+++ b/scripts/package-build/hostap/.gitignore
@@ -1,7 +1,2 @@
-hostap/
-wpa/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/hostap/
+/wpa/
diff --git a/scripts/package-build/hsflowd/.gitignore b/scripts/package-build/hsflowd/.gitignore
index d0964b29..aebf1d06 100644
--- a/scripts/package-build/hsflowd/.gitignore
+++ b/scripts/package-build/hsflowd/.gitignore
@@ -1,6 +1 @@
-host-sflow/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/host-sflow/
diff --git a/scripts/package-build/hsflowd/package.toml b/scripts/package-build/hsflowd/package.toml
index 75d320a7..823b0db3 100644
--- a/scripts/package-build/hsflowd/package.toml
+++ b/scripts/package-build/hsflowd/package.toml
@@ -1,8 +1,8 @@
[[packages]]
name = "host-sflow"
-commit_id = "v2.0.55-1"
+commit_id = "v2.1.11-5"
scm_url = "https://github.com/sflow/host-sflow.git"
-build_cmd = "make deb FEATURES='PCAP DROPMON DBUS'"
+build_cmd = "make deb FEATURES='PCAP DROPMON DBUS PSAMPLE VPP'"
-[packages.dependencies]
+[dependencies]
packages = ["libpcap0.8-dev"]
diff --git a/scripts/package-build/isc-dhcp/.gitignore b/scripts/package-build/isc-dhcp/.gitignore
index 66d17cc8..41aa96b8 100644
--- a/scripts/package-build/isc-dhcp/.gitignore
+++ b/scripts/package-build/isc-dhcp/.gitignore
@@ -1,7 +1 @@
-isc-dhcp/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/isc-dhcp/
diff --git a/scripts/package-build/isc-dhcp/package.toml b/scripts/package-build/isc-dhcp/package.toml
index 76a0e4a1..f07e71e3 100644
--- a/scripts/package-build/isc-dhcp/package.toml
+++ b/scripts/package-build/isc-dhcp/package.toml
@@ -3,5 +3,5 @@ name = "isc-dhcp"
commit_id = "debian/4.4.3-P1-4"
scm_url = "https://salsa.debian.org/debian/isc-dhcp"
-[packages.dependencies]
+[dependencies]
packages = ["libpam0g-dev"]
diff --git a/scripts/package-build/isc-dhcp/patches/0001-Add-support-for-raw-IP-interface-type.patch b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0001-Add-support-for-raw-IP-interface-type.patch
index c13569ad..c13569ad 100644
--- a/scripts/package-build/isc-dhcp/patches/0001-Add-support-for-raw-IP-interface-type.patch
+++ b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0001-Add-support-for-raw-IP-interface-type.patch
diff --git a/scripts/package-build/isc-dhcp/patches/0002-Checkpoint-improved-patch.patch b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0002-Checkpoint-improved-patch.patch
index 60b693f6..60b693f6 100644
--- a/scripts/package-build/isc-dhcp/patches/0002-Checkpoint-improved-patch.patch
+++ b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0002-Checkpoint-improved-patch.patch
diff --git a/scripts/package-build/isc-dhcp/patches/0003-fix-compilation-errors.patch b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0003-fix-compilation-errors.patch
index c66e0c7c..c66e0c7c 100644
--- a/scripts/package-build/isc-dhcp/patches/0003-fix-compilation-errors.patch
+++ b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0003-fix-compilation-errors.patch
diff --git a/scripts/package-build/isc-dhcp/patches/0004-add-support-for-ARPHRD_NONE-interface-type.patch b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0004-add-support-for-ARPHRD_NONE-interface-type.patch
index 32089b4d..32089b4d 100644
--- a/scripts/package-build/isc-dhcp/patches/0004-add-support-for-ARPHRD_NONE-interface-type.patch
+++ b/scripts/package-build/isc-dhcp/patches/isc-dhcp/0004-add-support-for-ARPHRD_NONE-interface-type.patch
diff --git a/scripts/package-build/kea/.gitignore b/scripts/package-build/kea/.gitignore
index 1f9d42c9..70219f63 100644
--- a/scripts/package-build/kea/.gitignore
+++ b/scripts/package-build/kea/.gitignore
@@ -1,7 +1 @@
-isc-kea/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/isc-kea/
diff --git a/scripts/package-build/kea/package.toml b/scripts/package-build/kea/package.toml
index 0bfce21e..872be441 100644
--- a/scripts/package-build/kea/package.toml
+++ b/scripts/package-build/kea/package.toml
@@ -1,4 +1,4 @@
[[packages]]
name = "isc-kea"
-commit_id = "debian/2.4.1-3"
+commit_id = "debian/2.6.1-2"
scm_url = "https://salsa.debian.org/debian/isc-kea"
diff --git a/scripts/package-build/kea/patches/isc-kea/0001-Add-multithreading-test-mode.patch b/scripts/package-build/kea/patches/isc-kea/0001-Add-multithreading-test-mode.patch
new file mode 100644
index 00000000..981e6f1d
--- /dev/null
+++ b/scripts/package-build/kea/patches/isc-kea/0001-Add-multithreading-test-mode.patch
@@ -0,0 +1,135 @@
+From cb2b064162e2d5bf09331c619abf76a40130ade1 Mon Sep 17 00:00:00 2001
+From: sarthurdev <s.arthur@vyos.io>
+Date: Wed, 2 Apr 2025 08:48:48 +0000
+Subject: [PATCH 1/2] Add multithreading test mode
+
+---
+ src/bin/dhcp4/json_config_parser.cc | 4 ++++
+ src/bin/dhcp6/json_config_parser.cc | 6 +++++-
+ src/lib/config/cmd_http_listener.cc | 3 +++
+ src/lib/tcp/mt_tcp_listener_mgr.cc | 3 +++
+ src/lib/util/multi_threading_mgr.cc | 3 ++-
+ src/lib/util/multi_threading_mgr.h | 19 +++++++++++++++++++
+ 6 files changed, 36 insertions(+), 2 deletions(-)
+
+diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc
+index c2e34c5..1350816 100644
+--- a/src/bin/dhcp4/json_config_parser.cc
++++ b/src/bin/dhcp4/json_config_parser.cc
+@@ -718,6 +718,10 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START)
+ .arg(server.redactConfig(config_set)->str());
+
++ if (check_only) {
++ MultiThreadingMgr::instance().setTestMode(true);
++ }
++
+ auto answer = processDhcp4Config(config_set);
+
+ int status_code = CONTROL_RESULT_SUCCESS;
+diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc
+index 671d69a..a74a568 100644
+--- a/src/bin/dhcp6/json_config_parser.cc
++++ b/src/bin/dhcp6/json_config_parser.cc
+@@ -850,6 +850,10 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
+ LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START)
+ .arg(server.redactConfig(config_set)->str());
+
++ if (check_only) {
++ MultiThreadingMgr::instance().setTestMode(true);
++ }
++
+ auto answer = processDhcp6Config(config_set);
+
+ int status_code = CONTROL_RESULT_SUCCESS;
+@@ -953,7 +957,7 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
+ // configuration. This will add created subnets and option values into
+ // the server's configuration.
+ // This operation should be exception safe but let's make sure.
+- if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
++ if (status_code == CONTROL_RESULT_SUCCESS && !check_only) {
+ try {
+
+ // Setup the command channel.
+diff --git a/src/lib/config/cmd_http_listener.cc b/src/lib/config/cmd_http_listener.cc
+index 9dfea59..394806e 100644
+--- a/src/lib/config/cmd_http_listener.cc
++++ b/src/lib/config/cmd_http_listener.cc
+@@ -40,6 +40,9 @@ CmdHttpListener::~CmdHttpListener() {
+
+ void
+ CmdHttpListener::start() {
++ if (MultiThreadingMgr::instance().isTestMode()) {
++ return;
++ }
+ // We must be in multi-threading mode.
+ if (!MultiThreadingMgr::instance().getMode()) {
+ isc_throw(InvalidOperation, "CmdHttpListener cannot be started"
+diff --git a/src/lib/tcp/mt_tcp_listener_mgr.cc b/src/lib/tcp/mt_tcp_listener_mgr.cc
+index e880284..4680717 100644
+--- a/src/lib/tcp/mt_tcp_listener_mgr.cc
++++ b/src/lib/tcp/mt_tcp_listener_mgr.cc
+@@ -40,6 +40,9 @@ MtTcpListenerMgr::~MtTcpListenerMgr() {
+
+ void
+ MtTcpListenerMgr::start() {
++ if (MultiThreadingMgr::instance().isTestMode()) {
++ return;
++ }
+ // We must be in multi-threading mode.
+ if (!MultiThreadingMgr::instance().getMode()) {
+ isc_throw(InvalidOperation, "MtTcpListenerMgr cannot be started"
+diff --git a/src/lib/util/multi_threading_mgr.cc b/src/lib/util/multi_threading_mgr.cc
+index d1526b9..cab284d 100644
+--- a/src/lib/util/multi_threading_mgr.cc
++++ b/src/lib/util/multi_threading_mgr.cc
+@@ -14,7 +14,8 @@ namespace isc {
+ namespace util {
+
+ MultiThreadingMgr::MultiThreadingMgr()
+- : enabled_(false), critical_section_count_(0), thread_pool_size_(0) {
++ : enabled_(false), test_mode_(false), critical_section_count_(0),
++ thread_pool_size_(0) {
+ }
+
+ MultiThreadingMgr::~MultiThreadingMgr() {
+diff --git a/src/lib/util/multi_threading_mgr.h b/src/lib/util/multi_threading_mgr.h
+index e86c488..f3da67b 100644
+--- a/src/lib/util/multi_threading_mgr.h
++++ b/src/lib/util/multi_threading_mgr.h
+@@ -154,6 +154,22 @@ public:
+ /// @param enabled The new mode.
+ void setMode(bool enabled);
+
++ /// @brief Sets or clears the test mode for @c MultiThreadingMgr.
++ ///
++ /// @param test_mode A flag which indicates that the @c MultiThreadingMgr is
++ /// in the test mode (if true), or not (if false).
++ void setTestMode(const bool test_mode) {
++ test_mode_ = test_mode;
++ }
++
++ /// @brief Checks if the @c MultiThreadingMgr is in the test mode.
++ ///
++ /// @return true if the @c MultiThreadingMgr is in the test mode, false
++ /// otherwise.
++ bool isTestMode() const {
++ return (test_mode_);
++ }
++
+ /// @brief Enter critical section.
+ ///
+ /// When entering @ref MultiThreadingCriticalSection, increment internal
+@@ -308,6 +324,9 @@ private:
+ /// otherwise.
+ bool enabled_;
+
++ /// @brief Indicates if the @c MultiThreadingMgr is in the test mode.
++ bool test_mode_;
++
+ /// @brief The critical section count.
+ ///
+ /// In case the configuration is applied within a
+--
+2.39.5
+
diff --git a/scripts/package-build/kea/patches/isc-kea/0002-Add-ping_check-hook-library.patch b/scripts/package-build/kea/patches/isc-kea/0002-Add-ping_check-hook-library.patch
new file mode 100644
index 00000000..c2f172ca
--- /dev/null
+++ b/scripts/package-build/kea/patches/isc-kea/0002-Add-ping_check-hook-library.patch
@@ -0,0 +1,13277 @@
+From 6f198a187195a7fa4ad2cf9d147532bd64724f65 Mon Sep 17 00:00:00 2001
+From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
+Date: Mon, 24 Mar 2025 19:38:34 +0100
+Subject: [PATCH] Add ping_check hook library
+
+---
+ configure.ac | 3 +
+ src/hooks/dhcp/Makefile.am | 2 +-
+ src/hooks/dhcp/ping_check/Doxyfile | 2568 +++++++++++++++++
+ src/hooks/dhcp/ping_check/Makefile.am | 104 +
+ src/hooks/dhcp/ping_check/config_cache.cc | 107 +
+ src/hooks/dhcp/ping_check/config_cache.h | 146 +
+ src/hooks/dhcp/ping_check/icmp_endpoint.h | 134 +
+ src/hooks/dhcp/ping_check/icmp_msg.cc | 112 +
+ src/hooks/dhcp/ping_check/icmp_msg.h | 223 ++
+ src/hooks/dhcp/ping_check/icmp_socket.h | 359 +++
+ .../dhcp/ping_check/libloadtests/.gitignore | 1 +
+ .../dhcp/ping_check/libloadtests/Makefile.am | 60 +
+ .../libloadtests/load_unload_unittests.cc | 107 +
+ .../dhcp/ping_check/libloadtests/meson.build | 21 +
+ .../ping_check/libloadtests/run_unittests.cc | 19 +
+ src/hooks/dhcp/ping_check/meson.build | 41 +
+ src/hooks/dhcp/ping_check/ping_channel.cc | 466 +++
+ src/hooks/dhcp/ping_check/ping_channel.h | 371 +++
+ src/hooks/dhcp/ping_check/ping_check.dox | 44 +
+ .../dhcp/ping_check/ping_check_callouts.cc | 240 ++
+ .../dhcp/ping_check/ping_check_config.cc | 98 +
+ src/hooks/dhcp/ping_check/ping_check_config.h | 134 +
+ src/hooks/dhcp/ping_check/ping_check_log.cc | 17 +
+ src/hooks/dhcp/ping_check/ping_check_log.h | 23 +
+ .../dhcp/ping_check/ping_check_messages.cc | 99 +
+ .../dhcp/ping_check/ping_check_messages.h | 50 +
+ .../dhcp/ping_check/ping_check_messages.mes | 229 ++
+ src/hooks/dhcp/ping_check/ping_check_mgr.cc | 798 +++++
+ src/hooks/dhcp/ping_check/ping_check_mgr.h | 436 +++
+ src/hooks/dhcp/ping_check/ping_context.cc | 237 ++
+ src/hooks/dhcp/ping_check/ping_context.h | 280 ++
+ .../dhcp/ping_check/ping_context_store.cc | 144 +
+ .../dhcp/ping_check/ping_context_store.h | 240 ++
+ src/hooks/dhcp/ping_check/tests/.gitignore | 1 +
+ src/hooks/dhcp/ping_check/tests/Makefile.am | 70 +
+ .../tests/config_cache_unittests.cc | 245 ++
+ .../tests/icmp_endpoint_unittests.cc | 44 +
+ .../ping_check/tests/icmp_msg_unittests.cc | 172 ++
+ .../ping_check/tests/icmp_socket_unittests.cc | 380 +++
+ src/hooks/dhcp/ping_check/tests/meson.build | 21 +
+ .../tests/ping_channel_unittests.cc | 821 ++++++
+ .../tests/ping_check_config_unittests.cc | 287 ++
+ .../tests/ping_check_mgr_unittests.cc | 1878 ++++++++++++
+ .../tests/ping_context_store_unittests.cc | 467 +++
+ .../tests/ping_context_unittests.cc | 146 +
+ .../dhcp/ping_check/tests/ping_test_utils.h | 396 +++
+ .../dhcp/ping_check/tests/run_unittests.cc | 19 +
+ src/hooks/dhcp/ping_check/version.cc | 17 +
+ 48 files changed, 12876 insertions(+), 1 deletion(-)
+ create mode 100644 src/hooks/dhcp/ping_check/Doxyfile
+ create mode 100644 src/hooks/dhcp/ping_check/Makefile.am
+ create mode 100644 src/hooks/dhcp/ping_check/config_cache.cc
+ create mode 100644 src/hooks/dhcp/ping_check/config_cache.h
+ create mode 100644 src/hooks/dhcp/ping_check/icmp_endpoint.h
+ create mode 100644 src/hooks/dhcp/ping_check/icmp_msg.cc
+ create mode 100644 src/hooks/dhcp/ping_check/icmp_msg.h
+ create mode 100644 src/hooks/dhcp/ping_check/icmp_socket.h
+ create mode 100644 src/hooks/dhcp/ping_check/libloadtests/.gitignore
+ create mode 100644 src/hooks/dhcp/ping_check/libloadtests/Makefile.am
+ create mode 100644 src/hooks/dhcp/ping_check/libloadtests/load_unload_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/libloadtests/meson.build
+ create mode 100644 src/hooks/dhcp/ping_check/libloadtests/run_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/meson.build
+ create mode 100644 src/hooks/dhcp/ping_check/ping_channel.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_channel.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check.dox
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_callouts.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_config.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_config.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_log.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_log.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_messages.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_messages.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_messages.mes
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_mgr.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_check_mgr.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_context.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_context.h
+ create mode 100644 src/hooks/dhcp/ping_check/ping_context_store.cc
+ create mode 100644 src/hooks/dhcp/ping_check/ping_context_store.h
+ create mode 100644 src/hooks/dhcp/ping_check/tests/.gitignore
+ create mode 100644 src/hooks/dhcp/ping_check/tests/Makefile.am
+ create mode 100644 src/hooks/dhcp/ping_check/tests/config_cache_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/icmp_endpoint_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/icmp_msg_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/icmp_socket_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/meson.build
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_channel_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_check_config_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_check_mgr_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_context_store_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_context_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/tests/ping_test_utils.h
+ create mode 100644 src/hooks/dhcp/ping_check/tests/run_unittests.cc
+ create mode 100644 src/hooks/dhcp/ping_check/version.cc
+
+diff --git a/configure.ac b/configure.ac
+index cc1b31af71..23c8eefb81 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1582,6 +1582,9 @@ AC_CONFIG_FILES([src/hooks/dhcp/lease_cmds/tests/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/mysql_cb/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/mysql_cb/libloadtests/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/mysql_cb/tests/Makefile])
++AC_CONFIG_FILES([src/hooks/dhcp/ping_check/Makefile])
++AC_CONFIG_FILES([src/hooks/dhcp/ping_check/libloadtests/Makefile])
++AC_CONFIG_FILES([src/hooks/dhcp/ping_check/tests/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/pgsql_cb/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/pgsql_cb/libloadtests/Makefile])
+ AC_CONFIG_FILES([src/hooks/dhcp/pgsql_cb/tests/Makefile])
+diff --git a/src/hooks/dhcp/Makefile.am b/src/hooks/dhcp/Makefile.am
+index 1b77976424..806e310a17 100644
+--- a/src/hooks/dhcp/Makefile.am
++++ b/src/hooks/dhcp/Makefile.am
+@@ -8,4 +8,4 @@ if HAVE_PGSQL
+ SUBDIRS += pgsql_cb
+ endif
+
+-SUBDIRS += run_script stat_cmds user_chk
++SUBDIRS += run_script stat_cmds user_chk ping_check
+diff --git a/src/hooks/dhcp/ping_check/Doxyfile b/src/hooks/dhcp/ping_check/Doxyfile
+new file mode 100644
+index 0000000000..7c8554b557
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/Doxyfile
+@@ -0,0 +1,2568 @@
++# Doxyfile 1.9.1
++
++# This file describes the settings to be used by the documentation system
++# doxygen (www.doxygen.org) for a project.
++#
++# All text after a double hash (##) is considered a comment and is placed in
++# front of the TAG it is preceding.
++#
++# All text after a single hash (#) is considered a comment and will be ignored.
++# The format is:
++# TAG = value [value, ...]
++# For lists, items can also be appended using:
++# TAG += value [value, ...]
++# Values that contain spaces should be placed between quotes (\" \").
++
++#---------------------------------------------------------------------------
++# Project related configuration options
++#---------------------------------------------------------------------------
++
++# This tag specifies the encoding used for all characters in the configuration
++# file that follow. The default is UTF-8 which is also the encoding used for all
++# text before the first occurrence of this tag. Doxygen uses libiconv (or the
++# iconv built into libc) for the transcoding. See
++# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
++# The default value is: UTF-8.
++
++DOXYFILE_ENCODING = UTF-8
++
++# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
++# double-quotes, unless you are using Doxywizard) that should identify the
++# project for which the documentation is generated. This name is used in the
++# title of most generated pages and in a few other places.
++# The default value is: My Project.
++
++PROJECT_NAME = "Kea Ping Check Hooks Library"
++
++# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
++# could be handy for archiving the generated documentation or if some version
++# control system is used.
++
++PROJECT_NUMBER =
++
++# Using the PROJECT_BRIEF tag one can provide an optional one line description
++# for a project that appears at the top of each page and should give viewer a
++# quick idea about the purpose of the project. Keep the description short.
++
++PROJECT_BRIEF =
++
++# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
++# in the documentation. The maximum height of the logo should not exceed 55
++# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
++# the logo to the output directory.
++
++PROJECT_LOGO = ../../../../../doc/images/kea-logo-100x70.png
++
++# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
++# into which the generated documentation will be written. If a relative path is
++# entered, it will be relative to the location where doxygen was started. If
++# left blank the current directory will be used.
++
++OUTPUT_DIRECTORY = html
++
++# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
++# directories (in 2 levels) under the output directory of each output format and
++# will distribute the generated files over these directories. Enabling this
++# option can be useful when feeding doxygen a huge amount of source files, where
++# putting all generated files in the same directory would otherwise causes
++# performance problems for the file system.
++# The default value is: NO.
++
++CREATE_SUBDIRS = YES
++
++# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
++# characters to appear in the names of generated files. If set to NO, non-ASCII
++# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
++# U+3044.
++# The default value is: NO.
++
++ALLOW_UNICODE_NAMES = NO
++
++# The OUTPUT_LANGUAGE tag is used to specify the language in which all
++# documentation generated by doxygen is written. Doxygen will use this
++# information to generate all constant output in the proper language.
++# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
++# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
++# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
++# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
++# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
++# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
++# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
++# Ukrainian and Vietnamese.
++# The default value is: English.
++
++OUTPUT_LANGUAGE = English
++
++# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
++# documentation generated by doxygen is written. Doxygen will use this
++# information to generate all generated output in the proper direction.
++# Possible values are: None, LTR, RTL and Context.
++# The default value is: None.
++
++OUTPUT_TEXT_DIRECTION = None
++
++# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
++# descriptions after the members that are listed in the file and class
++# documentation (similar to Javadoc). Set to NO to disable this.
++# The default value is: YES.
++
++BRIEF_MEMBER_DESC = YES
++
++# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
++# description of a member or function before the detailed description
++#
++# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
++# brief descriptions will be completely suppressed.
++# The default value is: YES.
++
++REPEAT_BRIEF = YES
++
++# This tag implements a quasi-intelligent brief description abbreviator that is
++# used to form the text in various listings. Each string in this list, if found
++# as the leading text of the brief description, will be stripped from the text
++# and the result, after processing the whole list, is used as the annotated
++# text. Otherwise, the brief description is used as-is. If left blank, the
++# following values are used ($name is automatically replaced with the name of
++# the entity):The $name class, The $name widget, The $name file, is, provides,
++# specifies, contains, represents, a, an and the.
++
++ABBREVIATE_BRIEF =
++
++# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
++# doxygen will generate a detailed section even if there is only a brief
++# description.
++# The default value is: NO.
++
++ALWAYS_DETAILED_SEC = NO
++
++# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
++# inherited members of a class in the documentation of that class as if those
++# members were ordinary class members. Constructors, destructors and assignment
++# operators of the base classes will not be shown.
++# The default value is: NO.
++
++INLINE_INHERITED_MEMB = NO
++
++# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
++# before files name in the file list and in the header files. If set to NO the
++# shortest path that makes the file name unique will be used
++# The default value is: YES.
++
++FULL_PATH_NAMES = NO
++
++# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
++# Stripping is only done if one of the specified strings matches the left-hand
++# part of the path. The tag can be used to show relative paths in the file list.
++# If left blank the directory from which doxygen is run is used as the path to
++# strip.
++#
++# Note that you can specify absolute paths here, but also relative paths, which
++# will be relative from the directory where doxygen is started.
++# This tag requires that the tag FULL_PATH_NAMES is set to YES.
++
++STRIP_FROM_PATH =
++
++# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
++# path mentioned in the documentation of a class, which tells the reader which
++# header file to include in order to use a class. If left blank only the name of
++# the header file containing the class definition is used. Otherwise one should
++# specify the list of include paths that are normally passed to the compiler
++# using the -I flag.
++
++STRIP_FROM_INC_PATH =
++
++# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
++# less readable) file names. This can be useful is your file systems doesn't
++# support long names like on DOS, Mac, or CD-ROM.
++# The default value is: NO.
++
++SHORT_NAMES = NO
++
++# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
++# first line (until the first dot) of a Javadoc-style comment as the brief
++# description. If set to NO, the Javadoc-style will behave just like regular Qt-
++# style comments (thus requiring an explicit @brief command for a brief
++# description.)
++# The default value is: NO.
++
++JAVADOC_AUTOBRIEF = YES
++
++# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
++# such as
++# /***************
++# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
++# Javadoc-style will behave just like regular comments and it will not be
++# interpreted by doxygen.
++# The default value is: NO.
++
++JAVADOC_BANNER = NO
++
++# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
++# line (until the first dot) of a Qt-style comment as the brief description. If
++# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
++# requiring an explicit \brief command for a brief description.)
++# The default value is: NO.
++
++QT_AUTOBRIEF = NO
++
++# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
++# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
++# a brief description. This used to be the default behavior. The new default is
++# to treat a multi-line C++ comment block as a detailed description. Set this
++# tag to YES if you prefer the old behavior instead.
++#
++# Note that setting this tag to YES also means that rational rose comments are
++# not recognized any more.
++# The default value is: NO.
++
++MULTILINE_CPP_IS_BRIEF = NO
++
++# By default Python docstrings are displayed as preformatted text and doxygen's
++# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
++# doxygen's special commands can be used and the contents of the docstring
++# documentation blocks is shown as doxygen documentation.
++# The default value is: YES.
++
++PYTHON_DOCSTRING = YES
++
++# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
++# documentation from any documented member that it re-implements.
++# The default value is: YES.
++
++INHERIT_DOCS = YES
++
++# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
++# page for each member. If set to NO, the documentation of a member will be part
++# of the file/class/namespace that contains it.
++# The default value is: NO.
++
++SEPARATE_MEMBER_PAGES = NO
++
++# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
++# uses this value to replace tabs by spaces in code fragments.
++# Minimum value: 1, maximum value: 16, default value: 4.
++
++TAB_SIZE = 4
++
++# This tag can be used to specify a number of aliases that act as commands in
++# the documentation. An alias has the form:
++# name=value
++# For example adding
++# "sideeffect=@par Side Effects:\n"
++# will allow you to put the command \sideeffect (or @sideeffect) in the
++# documentation, which will result in a user-defined paragraph with heading
++# "Side Effects:". You can put \n's in the value part of an alias to insert
++# newlines (in the resulting output). You can put ^^ in the value part of an
++# alias to insert a newline as if a physical newline was in the original file.
++# When you need a literal { or } or , in the value part of an alias you have to
++# escape them by means of a backslash (\), this can lead to conflicts with the
++# commands \{ and \} for these it is advised to use the version @{ and @} or use
++# a double escape (\\{ and \\})
++
++ALIASES =
++
++# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
++# only. Doxygen will then generate output that is more tailored for C. For
++# instance, some of the names that are used will be different. The list of all
++# members will be omitted, etc.
++# The default value is: NO.
++
++OPTIMIZE_OUTPUT_FOR_C = NO
++
++# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
++# Python sources only. Doxygen will then generate output that is more tailored
++# for that language. For instance, namespaces will be presented as packages,
++# qualified scopes will look different, etc.
++# The default value is: NO.
++
++OPTIMIZE_OUTPUT_JAVA = NO
++
++# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
++# sources. Doxygen will then generate output that is tailored for Fortran.
++# The default value is: NO.
++
++OPTIMIZE_FOR_FORTRAN = NO
++
++# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
++# sources. Doxygen will then generate output that is tailored for VHDL.
++# The default value is: NO.
++
++OPTIMIZE_OUTPUT_VHDL = NO
++
++# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
++# sources only. Doxygen will then generate output that is more tailored for that
++# language. For instance, namespaces will be presented as modules, types will be
++# separated into more groups, etc.
++# The default value is: NO.
++
++OPTIMIZE_OUTPUT_SLICE = NO
++
++# Doxygen selects the parser to use depending on the extension of the files it
++# parses. With this tag you can assign which parser to use for a given
++# extension. Doxygen has a built-in mapping, but you can override or extend it
++# using this tag. The format is ext=language, where ext is a file extension, and
++# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
++# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
++# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
++# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
++# tries to guess whether the code is fixed or free formatted code, this is the
++# default for Fortran type files). For instance to make doxygen treat .inc files
++# as Fortran files (default is PHP), and .f files as C (default is Fortran),
++# use: inc=Fortran f=C.
++#
++# Note: For files without extension you can use no_extension as a placeholder.
++#
++# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
++# the files are not read by doxygen. When specifying no_extension you should add
++# * to the FILE_PATTERNS.
++#
++# Note see also the list of default file extension mappings.
++
++EXTENSION_MAPPING =
++
++# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
++# according to the Markdown format, which allows for more readable
++# documentation. See https://daringfireball.net/projects/markdown/ for details.
++# The output of markdown processing is further processed by doxygen, so you can
++# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
++# case of backward compatibilities issues.
++# The default value is: YES.
++
++MARKDOWN_SUPPORT = YES
++
++# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
++# to that level are automatically included in the table of contents, even if
++# they do not have an id attribute.
++# Note: This feature currently applies only to Markdown headings.
++# Minimum value: 0, maximum value: 99, default value: 5.
++# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
++
++TOC_INCLUDE_HEADINGS = 5
++
++# When enabled doxygen tries to link words that correspond to documented
++# classes, or namespaces to their corresponding documentation. Such a link can
++# be prevented in individual cases by putting a % sign in front of the word or
++# globally by setting AUTOLINK_SUPPORT to NO.
++# The default value is: YES.
++
++AUTOLINK_SUPPORT = YES
++
++# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
++# to include (a tag file for) the STL sources as input, then you should set this
++# tag to YES in order to let doxygen match functions declarations and
++# definitions whose arguments contain STL classes (e.g. func(std::string);
++# versus func(std::string) {}). This also make the inheritance and collaboration
++# diagrams that involve STL classes more complete and accurate.
++# The default value is: NO.
++
++BUILTIN_STL_SUPPORT = YES
++
++# If you use Microsoft's C++/CLI language, you should set this option to YES to
++# enable parsing support.
++# The default value is: NO.
++
++CPP_CLI_SUPPORT = NO
++
++# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
++# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
++# will parse them like normal C++ but will assume all classes use public instead
++# of private inheritance when no explicit protection keyword is present.
++# The default value is: NO.
++
++SIP_SUPPORT = NO
++
++# For Microsoft's IDL there are propget and propput attributes to indicate
++# getter and setter methods for a property. Setting this option to YES will make
++# doxygen to replace the get and set methods by a property in the documentation.
++# This will only work if the methods are indeed getting or setting a simple
++# type. If this is not the case, or you want to show the methods anyway, you
++# should set this option to NO.
++# The default value is: YES.
++
++IDL_PROPERTY_SUPPORT = YES
++
++# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
++# tag is set to YES then doxygen will reuse the documentation of the first
++# member in the group (if any) for the other members of the group. By default
++# all members of a group must be documented explicitly.
++# The default value is: NO.
++
++DISTRIBUTE_GROUP_DOC = NO
++
++# If one adds a struct or class to a group and this option is enabled, then also
++# any nested class or struct is added to the same group. By default this option
++# is disabled and one has to add nested compounds explicitly via \ingroup.
++# The default value is: NO.
++
++GROUP_NESTED_COMPOUNDS = NO
++
++# Set the SUBGROUPING tag to YES to allow class member groups of the same type
++# (for instance a group of public functions) to be put as a subgroup of that
++# type (e.g. under the Public Functions section). Set it to NO to prevent
++# subgrouping. Alternatively, this can be done per class using the
++# \nosubgrouping command.
++# The default value is: YES.
++
++SUBGROUPING = YES
++
++# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
++# are shown inside the group in which they are included (e.g. using \ingroup)
++# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
++# and RTF).
++#
++# Note that this feature does not work in combination with
++# SEPARATE_MEMBER_PAGES.
++# The default value is: NO.
++
++INLINE_GROUPED_CLASSES = NO
++
++# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
++# with only public data fields or simple typedef fields will be shown inline in
++# the documentation of the scope in which they are defined (i.e. file,
++# namespace, or group documentation), provided this scope is documented. If set
++# to NO, structs, classes, and unions are shown on a separate page (for HTML and
++# Man pages) or section (for LaTeX and RTF).
++# The default value is: NO.
++
++INLINE_SIMPLE_STRUCTS = NO
++
++# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
++# enum is documented as struct, union, or enum with the name of the typedef. So
++# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
++# with name TypeT. When disabled the typedef will appear as a member of a file,
++# namespace, or class. And the struct will be named TypeS. This can typically be
++# useful for C code in case the coding convention dictates that all compound
++# types are typedef'ed and only the typedef is referenced, never the tag name.
++# The default value is: NO.
++
++TYPEDEF_HIDES_STRUCT = NO
++
++# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
++# cache is used to resolve symbols given their name and scope. Since this can be
++# an expensive process and often the same symbol appears multiple times in the
++# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
++# doxygen will become slower. If the cache is too large, memory is wasted. The
++# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
++# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
++# symbols. At the end of a run doxygen will report the cache usage and suggest
++# the optimal cache size from a speed point of view.
++# Minimum value: 0, maximum value: 9, default value: 0.
++
++LOOKUP_CACHE_SIZE = 0
++
++# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
++# during processing. When set to 0 doxygen will based this on the number of
++# cores available in the system. You can set it explicitly to a value larger
++# than 0 to get more control over the balance between CPU load and processing
++# speed. At this moment only the input processing can be done using multiple
++# threads. Since this is still an experimental feature the default is set to 1,
++# which effectively disables parallel processing. Please report any issues you
++# encounter. Generating dot graphs in parallel is controlled by the
++# DOT_NUM_THREADS setting.
++# Minimum value: 0, maximum value: 32, default value: 1.
++
++NUM_PROC_THREADS = 1
++
++#---------------------------------------------------------------------------
++# Build related configuration options
++#---------------------------------------------------------------------------
++
++# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
++# documentation are documented, even if no documentation was available. Private
++# class members and static file members will be hidden unless the
++# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
++# Note: This will also disable the warnings about undocumented members that are
++# normally produced when WARNINGS is set to YES.
++# The default value is: NO.
++
++EXTRACT_ALL = YES
++
++# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
++# be included in the documentation.
++# The default value is: NO.
++
++EXTRACT_PRIVATE = NO
++
++# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
++# methods of a class will be included in the documentation.
++# The default value is: NO.
++
++EXTRACT_PRIV_VIRTUAL = NO
++
++# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
++# scope will be included in the documentation.
++# The default value is: NO.
++
++EXTRACT_PACKAGE = NO
++
++# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
++# included in the documentation.
++# The default value is: NO.
++
++EXTRACT_STATIC = NO
++
++# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
++# locally in source files will be included in the documentation. If set to NO,
++# only classes defined in header files are included. Does not have any effect
++# for Java sources.
++# The default value is: YES.
++
++EXTRACT_LOCAL_CLASSES = YES
++
++# This flag is only useful for Objective-C code. If set to YES, local methods,
++# which are defined in the implementation section but not in the interface are
++# included in the documentation. If set to NO, only methods in the interface are
++# included.
++# The default value is: NO.
++
++EXTRACT_LOCAL_METHODS = NO
++
++# If this flag is set to YES, the members of anonymous namespaces will be
++# extracted and appear in the documentation as a namespace called
++# 'anonymous_namespace{file}', where file will be replaced with the base name of
++# the file that contains the anonymous namespace. By default anonymous namespace
++# are hidden.
++# The default value is: NO.
++
++EXTRACT_ANON_NSPACES = NO
++
++# If this flag is set to YES, the name of an unnamed parameter in a declaration
++# will be determined by the corresponding definition. By default unnamed
++# parameters remain unnamed in the output.
++# The default value is: YES.
++
++RESOLVE_UNNAMED_PARAMS = YES
++
++# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
++# undocumented members inside documented classes or files. If set to NO these
++# members will be included in the various overviews, but no documentation
++# section is generated. This option has no effect if EXTRACT_ALL is enabled.
++# The default value is: NO.
++
++HIDE_UNDOC_MEMBERS = NO
++
++# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
++# undocumented classes that are normally visible in the class hierarchy. If set
++# to NO, these classes will be included in the various overviews. This option
++# has no effect if EXTRACT_ALL is enabled.
++# The default value is: NO.
++
++HIDE_UNDOC_CLASSES = NO
++
++# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
++# declarations. If set to NO, these declarations will be included in the
++# documentation.
++# The default value is: NO.
++
++HIDE_FRIEND_COMPOUNDS = NO
++
++# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
++# documentation blocks found inside the body of a function. If set to NO, these
++# blocks will be appended to the function's detailed documentation block.
++# The default value is: NO.
++
++HIDE_IN_BODY_DOCS = NO
++
++# The INTERNAL_DOCS tag determines if documentation that is typed after a
++# \internal command is included. If the tag is set to NO then the documentation
++# will be excluded. Set it to YES to include the internal documentation.
++# The default value is: NO.
++
++INTERNAL_DOCS = NO
++
++# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
++# able to match the capabilities of the underlying filesystem. In case the
++# filesystem is case sensitive (i.e. it supports files in the same directory
++# whose names only differ in casing), the option must be set to YES to properly
++# deal with such files in case they appear in the input. For filesystems that
++# are not case sensitive the option should be be set to NO to properly deal with
++# output files written for symbols that only differ in casing, such as for two
++# classes, one named CLASS and the other named Class, and to also support
++# references to files without having to specify the exact matching casing. On
++# Windows (including Cygwin) and MacOS, users should typically set this option
++# to NO, whereas on Linux or other Unix flavors it should typically be set to
++# YES.
++# The default value is: system dependent.
++
++CASE_SENSE_NAMES = YES
++
++# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
++# their full class and namespace scopes in the documentation. If set to YES, the
++# scope will be hidden.
++# The default value is: NO.
++
++HIDE_SCOPE_NAMES = NO
++
++# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
++# append additional text to a page's title, such as Class Reference. If set to
++# YES the compound reference will be hidden.
++# The default value is: NO.
++
++HIDE_COMPOUND_REFERENCE= NO
++
++# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
++# the files that are included by a file in the documentation of that file.
++# The default value is: YES.
++
++SHOW_INCLUDE_FILES = YES
++
++# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
++# grouped member an include statement to the documentation, telling the reader
++# which file to include in order to use the member.
++# The default value is: NO.
++
++SHOW_GROUPED_MEMB_INC = NO
++
++# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
++# files with double quotes in the documentation rather than with sharp brackets.
++# The default value is: NO.
++
++FORCE_LOCAL_INCLUDES = NO
++
++# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
++# documentation for inline members.
++# The default value is: YES.
++
++INLINE_INFO = YES
++
++# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
++# (detailed) documentation of file and class members alphabetically by member
++# name. If set to NO, the members will appear in declaration order.
++# The default value is: YES.
++
++SORT_MEMBER_DOCS = YES
++
++# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
++# descriptions of file, namespace and class members alphabetically by member
++# name. If set to NO, the members will appear in declaration order. Note that
++# this will also influence the order of the classes in the class list.
++# The default value is: NO.
++
++SORT_BRIEF_DOCS = YES
++
++# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
++# (brief and detailed) documentation of class members so that constructors and
++# destructors are listed first. If set to NO the constructors will appear in the
++# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
++# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
++# member documentation.
++# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
++# detailed member documentation.
++# The default value is: NO.
++
++SORT_MEMBERS_CTORS_1ST = YES
++
++# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
++# of group names into alphabetical order. If set to NO the group names will
++# appear in their defined order.
++# The default value is: NO.
++
++SORT_GROUP_NAMES = YES
++
++# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
++# fully-qualified names, including namespaces. If set to NO, the class list will
++# be sorted only by class name, not including the namespace part.
++# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
++# Note: This option applies only to the class list, not to the alphabetical
++# list.
++# The default value is: NO.
++
++SORT_BY_SCOPE_NAME = NO
++
++# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
++# type resolution of all parameters of a function it will reject a match between
++# the prototype and the implementation of a member function even if there is
++# only one candidate or it is obvious which candidate to choose by doing a
++# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
++# accept a match between prototype and implementation in such cases.
++# The default value is: NO.
++
++STRICT_PROTO_MATCHING = NO
++
++# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
++# list. This list is created by putting \todo commands in the documentation.
++# The default value is: YES.
++
++GENERATE_TODOLIST = YES
++
++# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
++# list. This list is created by putting \test commands in the documentation.
++# The default value is: YES.
++
++GENERATE_TESTLIST = YES
++
++# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
++# list. This list is created by putting \bug commands in the documentation.
++# The default value is: YES.
++
++GENERATE_BUGLIST = YES
++
++# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
++# the deprecated list. This list is created by putting \deprecated commands in
++# the documentation.
++# The default value is: YES.
++
++GENERATE_DEPRECATEDLIST= YES
++
++# The ENABLED_SECTIONS tag can be used to enable conditional documentation
++# sections, marked by \if <section_label> ... \endif and \cond <section_label>
++# ... \endcond blocks.
++
++ENABLED_SECTIONS =
++
++# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
++# initial value of a variable or macro / define can have for it to appear in the
++# documentation. If the initializer consists of more lines than specified here
++# it will be hidden. Use a value of 0 to hide initializers completely. The
++# appearance of the value of individual variables and macros / defines can be
++# controlled using \showinitializer or \hideinitializer command in the
++# documentation regardless of this setting.
++# Minimum value: 0, maximum value: 10000, default value: 30.
++
++MAX_INITIALIZER_LINES = 30
++
++# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
++# the bottom of the documentation of classes and structs. If set to YES, the
++# list will mention the files that were used to generate the documentation.
++# The default value is: YES.
++
++SHOW_USED_FILES = YES
++
++# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
++# will remove the Files entry from the Quick Index and from the Folder Tree View
++# (if specified).
++# The default value is: YES.
++
++SHOW_FILES = YES
++
++# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
++# page. This will remove the Namespaces entry from the Quick Index and from the
++# Folder Tree View (if specified).
++# The default value is: YES.
++
++SHOW_NAMESPACES = YES
++
++# The FILE_VERSION_FILTER tag can be used to specify a program or script that
++# doxygen should invoke to get the current version for each file (typically from
++# the version control system). Doxygen will invoke the program by executing (via
++# popen()) the command command input-file, where command is the value of the
++# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
++# by doxygen. Whatever the program writes to standard output is used as the file
++# version. For an example see the documentation.
++
++FILE_VERSION_FILTER =
++
++# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
++# by doxygen. The layout file controls the global structure of the generated
++# output files in an output format independent way. To create the layout file
++# that represents doxygen's defaults, run doxygen with the -l option. You can
++# optionally specify a file name after the option, if omitted DoxygenLayout.xml
++# will be used as the name of the layout file.
++#
++# Note that if you run doxygen from a directory containing a file called
++# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
++# tag is left empty.
++
++LAYOUT_FILE =
++
++# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
++# the reference definitions. This must be a list of .bib files. The .bib
++# extension is automatically appended if omitted. This requires the bibtex tool
++# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
++# For LaTeX the style of the bibliography can be controlled using
++# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
++# search path. See also \cite for info how to create references.
++
++CITE_BIB_FILES =
++
++#---------------------------------------------------------------------------
++# Configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++
++# The QUIET tag can be used to turn on/off the messages that are generated to
++# standard output by doxygen. If QUIET is set to YES this implies that the
++# messages are off.
++# The default value is: NO.
++
++QUIET = YES
++
++# The WARNINGS tag can be used to turn on/off the warning messages that are
++# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
++# this implies that the warnings are on.
++#
++# Tip: Turn warnings on while writing the documentation.
++# The default value is: YES.
++
++WARNINGS = YES
++
++# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
++# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
++# will automatically be disabled.
++# The default value is: YES.
++
++WARN_IF_UNDOCUMENTED = YES
++
++# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
++# potential errors in the documentation, such as not documenting some parameters
++# in a documented function, or documenting parameters that don't exist or using
++# markup commands wrongly.
++# The default value is: YES.
++
++WARN_IF_DOC_ERROR = YES
++
++# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
++# are documented, but have no documentation for their parameters or return
++# value. If set to NO, doxygen will only warn about wrong or incomplete
++# parameter documentation, but not about the absence of documentation. If
++# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
++# The default value is: NO.
++
++WARN_NO_PARAMDOC = NO
++
++# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
++# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
++# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
++# at the end of the doxygen process doxygen will return with a non-zero status.
++# Possible values are: NO, YES and FAIL_ON_WARNINGS.
++# The default value is: NO.
++
++WARN_AS_ERROR = NO
++
++# The WARN_FORMAT tag determines the format of the warning messages that doxygen
++# can produce. The string should contain the $file, $line, and $text tags, which
++# will be replaced by the file and line number from which the warning originated
++# and the warning text. Optionally the format may contain $version, which will
++# be replaced by the version of the file (if it could be obtained via
++# FILE_VERSION_FILTER)
++# The default value is: $file:$line: $text.
++
++WARN_FORMAT = "$file:$line: $text"
++
++# The WARN_LOGFILE tag can be used to specify a file to which warning and error
++# messages should be written. If left blank the output is written to standard
++# error (stderr).
++
++WARN_LOGFILE =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the input files
++#---------------------------------------------------------------------------
++
++# The INPUT tag is used to specify the files and/or directories that contain
++# documented source files. You may enter file names like myfile.cpp or
++# directories like /usr/src/myproject. Separate the files or directories with
++# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
++# Note: If this tag is empty the current directory is searched.
++
++INPUT =
++
++# This tag can be used to specify the character encoding of the source files
++# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
++# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
++# documentation (see:
++# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
++# The default value is: UTF-8.
++
++INPUT_ENCODING = UTF-8
++
++# If the value of the INPUT tag contains directories, you can use the
++# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
++# *.h) to filter out the source-files in the directories.
++#
++# Note that for custom extensions or not directly supported extensions you also
++# need to set EXTENSION_MAPPING for the extension otherwise the files are not
++# read by doxygen.
++#
++# Note the list of default checked file patterns might differ from the list of
++# default file extension mappings.
++#
++# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
++# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
++# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
++# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
++# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
++# *.ucf, *.qsf and *.ice.
++
++FILE_PATTERNS = *.c \
++ *.cc \
++ *.h \
++ *.hpp \
++ *.dox
++
++# The RECURSIVE tag can be used to specify whether or not subdirectories should
++# be searched for input files as well.
++# The default value is: NO.
++
++RECURSIVE = NO
++
++# The EXCLUDE tag can be used to specify files and/or directories that should be
++# excluded from the INPUT source files. This way you can easily exclude a
++# subdirectory from a directory tree whose root is specified with the INPUT tag.
++#
++# Note that relative paths are relative to the directory from which doxygen is
++# run.
++
++EXCLUDE =
++
++# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
++# directories that are symbolic links (a Unix file system feature) are excluded
++# from the input.
++# The default value is: NO.
++
++EXCLUDE_SYMLINKS = NO
++
++# If the value of the INPUT tag contains directories, you can use the
++# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
++# certain files from those directories.
++#
++# Note that the wildcards are matched against the file with absolute path, so to
++# exclude all test directories for example use the pattern */test/*
++
++EXCLUDE_PATTERNS =
++
++# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
++# (namespaces, classes, functions, etc.) that should be excluded from the
++# output. The symbol name can be a fully qualified name, a word, or if the
++# wildcard * is used, a substring. Examples: ANamespace, AClass,
++# AClass::ANamespace, ANamespace::*Test
++#
++# Note that the wildcards are matched against the file with absolute path, so to
++# exclude all test directories use the pattern */test/*
++
++EXCLUDE_SYMBOLS =
++
++# The EXAMPLE_PATH tag can be used to specify one or more files or directories
++# that contain example code fragments that are included (see the \include
++# command).
++
++EXAMPLE_PATH =
++
++# If the value of the EXAMPLE_PATH tag contains directories, you can use the
++# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
++# *.h) to filter out the source-files in the directories. If left blank all
++# files are included.
++
++EXAMPLE_PATTERNS =
++
++# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
++# searched for input files to be used with the \include or \dontinclude commands
++# irrespective of the value of the RECURSIVE tag.
++# The default value is: NO.
++
++EXAMPLE_RECURSIVE = NO
++
++# The IMAGE_PATH tag can be used to specify one or more files or directories
++# that contain images that are to be included in the documentation (see the
++# \image command).
++
++IMAGE_PATH = ../../../../../doc/images
++
++# The INPUT_FILTER tag can be used to specify a program that doxygen should
++# invoke to filter for each input file. Doxygen will invoke the filter program
++# by executing (via popen()) the command:
++#
++# <filter> <input-file>
++#
++# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
++# name of an input file. Doxygen will then use the output that the filter
++# program writes to standard output. If FILTER_PATTERNS is specified, this tag
++# will be ignored.
++#
++# Note that the filter must not add or remove lines; it is applied before the
++# code is scanned, but not when the output code is generated. If lines are added
++# or removed, the anchors will not be placed correctly.
++#
++# Note that for custom extensions or not directly supported extensions you also
++# need to set EXTENSION_MAPPING for the extension otherwise the files are not
++# properly processed by doxygen.
++
++INPUT_FILTER =
++
++# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
++# basis. Doxygen will compare the file name with each pattern and apply the
++# filter if there is a match. The filters are a list of the form: pattern=filter
++# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
++# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
++# patterns match the file name, INPUT_FILTER is applied.
++#
++# Note that for custom extensions or not directly supported extensions you also
++# need to set EXTENSION_MAPPING for the extension otherwise the files are not
++# properly processed by doxygen.
++
++FILTER_PATTERNS =
++
++# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
++# INPUT_FILTER) will also be used to filter the input files that are used for
++# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
++# The default value is: NO.
++
++FILTER_SOURCE_FILES = NO
++
++# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
++# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
++# it is also possible to disable source filtering for a specific pattern using
++# *.ext= (so without naming a filter).
++# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
++
++FILTER_SOURCE_PATTERNS =
++
++# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
++# is part of the input, its contents will be placed on the main page
++# (index.html). This can be useful if you have a project on for instance GitHub
++# and want to reuse the introduction page also for the doxygen output.
++
++USE_MDFILE_AS_MAINPAGE =
++
++#---------------------------------------------------------------------------
++# Configuration options related to source browsing
++#---------------------------------------------------------------------------
++
++# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
++# generated. Documented entities will be cross-referenced with these sources.
++#
++# Note: To get rid of all source code in the generated output, make sure that
++# also VERBATIM_HEADERS is set to NO.
++# The default value is: NO.
++
++SOURCE_BROWSER = YES
++
++# Setting the INLINE_SOURCES tag to YES will include the body of functions,
++# classes and enums directly into the documentation.
++# The default value is: NO.
++
++INLINE_SOURCES = NO
++
++# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
++# special comment blocks from generated source code fragments. Normal C, C++ and
++# Fortran comments will always remain visible.
++# The default value is: YES.
++
++STRIP_CODE_COMMENTS = YES
++
++# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
++# entity all documented functions referencing it will be listed.
++# The default value is: NO.
++
++REFERENCED_BY_RELATION = YES
++
++# If the REFERENCES_RELATION tag is set to YES then for each documented function
++# all documented entities called/used by that function will be listed.
++# The default value is: NO.
++
++REFERENCES_RELATION = YES
++
++# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
++# to YES then the hyperlinks from functions in REFERENCES_RELATION and
++# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
++# link to the documentation.
++# The default value is: YES.
++
++REFERENCES_LINK_SOURCE = YES
++
++# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
++# source code will show a tooltip with additional information such as prototype,
++# brief description and links to the definition and documentation. Since this
++# will make the HTML file larger and loading of large files a bit slower, you
++# can opt to disable this feature.
++# The default value is: YES.
++# This tag requires that the tag SOURCE_BROWSER is set to YES.
++
++SOURCE_TOOLTIPS = YES
++
++# If the USE_HTAGS tag is set to YES then the references to source code will
++# point to the HTML generated by the htags(1) tool instead of doxygen built-in
++# source browser. The htags tool is part of GNU's global source tagging system
++# (see https://www.gnu.org/software/global/global.html). You will need version
++# 4.8.6 or higher.
++#
++# To use it do the following:
++# - Install the latest version of global
++# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
++# - Make sure the INPUT points to the root of the source tree
++# - Run doxygen as normal
++#
++# Doxygen will invoke htags (and that will in turn invoke gtags), so these
++# tools must be available from the command line (i.e. in the search path).
++#
++# The result: instead of the source browser generated by doxygen, the links to
++# source code will now point to the output of htags.
++# The default value is: NO.
++# This tag requires that the tag SOURCE_BROWSER is set to YES.
++
++USE_HTAGS = NO
++
++# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
++# verbatim copy of the header file for each class for which an include is
++# specified. Set to NO to disable this.
++# See also: Section \class.
++# The default value is: YES.
++
++VERBATIM_HEADERS = YES
++
++#---------------------------------------------------------------------------
++# Configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++
++# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
++# compounds will be generated. Enable this if the project contains a lot of
++# classes, structs, unions or interfaces.
++# The default value is: YES.
++
++ALPHABETICAL_INDEX = YES
++
++# In case all classes in a project start with a common prefix, all classes will
++# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
++# can be used to specify a prefix (or a list of prefixes) that should be ignored
++# while generating the index headers.
++# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
++
++IGNORE_PREFIX =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the HTML output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
++# The default value is: YES.
++
++GENERATE_HTML = YES
++
++# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
++# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
++# it.
++# The default directory is: html.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_OUTPUT = ../html
++
++# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
++# generated HTML page (for example: .htm, .php, .asp).
++# The default value is: .html.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_FILE_EXTENSION = .html
++
++# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
++# each generated HTML page. If the tag is left blank doxygen will generate a
++# standard header.
++#
++# To get valid HTML the header file that includes any scripts and style sheets
++# that doxygen needs, which is dependent on the configuration options used (e.g.
++# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
++# default header using
++# doxygen -w html new_header.html new_footer.html new_stylesheet.css
++# YourConfigFile
++# and then modify the file new_header.html. See also section "Doxygen usage"
++# for information on how to generate the default header that doxygen normally
++# uses.
++# Note: The header is subject to change so you typically have to regenerate the
++# default header when upgrading to a newer version of doxygen. For a description
++# of the possible markers and block names see the documentation.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_HEADER =
++
++# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
++# generated HTML page. If the tag is left blank doxygen will generate a standard
++# footer. See HTML_HEADER for more information on how to generate a default
++# footer and what special commands can be used inside the footer. See also
++# section "Doxygen usage" for information on how to generate the default footer
++# that doxygen normally uses.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_FOOTER =
++
++# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
++# sheet that is used by each HTML page. It can be used to fine-tune the look of
++# the HTML output. If left blank doxygen will generate a default style sheet.
++# See also section "Doxygen usage" for information on how to generate the style
++# sheet that doxygen normally uses.
++# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
++# it is more robust and this tag (HTML_STYLESHEET) will in the future become
++# obsolete.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_STYLESHEET =
++
++# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
++# cascading style sheets that are included after the standard style sheets
++# created by doxygen. Using this option one can overrule certain style aspects.
++# This is preferred over using HTML_STYLESHEET since it does not replace the
++# standard style sheet and is therefore more robust against future updates.
++# Doxygen will copy the style sheet files to the output directory.
++# Note: The order of the extra style sheet files is of importance (e.g. the last
++# style sheet in the list overrules the setting of the previous ones in the
++# list). For an example see the documentation.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_EXTRA_STYLESHEET =
++
++# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
++# other source files which should be copied to the HTML output directory. Note
++# that these files will be copied to the base HTML output directory. Use the
++# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
++# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
++# files will be copied as-is; there are no commands or markers available.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_EXTRA_FILES =
++
++# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
++# will adjust the colors in the style sheet and background images according to
++# this color. Hue is specified as an angle on a colorwheel, see
++# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
++# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
++# purple, and 360 is red again.
++# Minimum value: 0, maximum value: 359, default value: 220.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_COLORSTYLE_HUE = 148
++
++# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
++# in the HTML output. For a value of 0 the output will use grayscales only. A
++# value of 255 will produce the most vivid colors.
++# Minimum value: 0, maximum value: 255, default value: 100.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_COLORSTYLE_SAT = 93
++
++# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
++# luminance component of the colors in the HTML output. Values below 100
++# gradually make the output lighter, whereas values above 100 make the output
++# darker. The value divided by 100 is the actual gamma applied, so 80 represents
++# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
++# change the gamma.
++# Minimum value: 40, maximum value: 240, default value: 80.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_COLORSTYLE_GAMMA = 80
++
++# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
++# page will contain the date and time when the page was generated. Setting this
++# to YES can help to show when doxygen was last run and thus if the
++# documentation is up to date.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_TIMESTAMP = YES
++
++# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
++# documentation will contain a main index with vertical navigation menus that
++# are dynamically created via JavaScript. If disabled, the navigation index will
++# consists of multiple levels of tabs that are statically embedded in every HTML
++# page. Disable this option to support browsers that do not have JavaScript,
++# like the Qt help browser.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_DYNAMIC_MENUS = YES
++
++# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
++# documentation will contain sections that can be hidden and shown after the
++# page has loaded.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_DYNAMIC_SECTIONS = YES
++
++# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
++# shown in the various tree structured indices initially; the user can expand
++# and collapse entries dynamically later on. Doxygen will expand the tree to
++# such a level that at most the specified number of entries are visible (unless
++# a fully collapsed tree already exceeds this amount). So setting the number of
++# entries 1 will produce a full collapsed tree by default. 0 is a special value
++# representing an infinite number of entries and will result in a full expanded
++# tree by default.
++# Minimum value: 0, maximum value: 9999, default value: 100.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_INDEX_NUM_ENTRIES = 100
++
++# If the GENERATE_DOCSET tag is set to YES, additional index files will be
++# generated that can be used as input for Apple's Xcode 3 integrated development
++# environment (see:
++# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
++# create a documentation set, doxygen will generate a Makefile in the HTML
++# output directory. Running make will produce the docset in that directory and
++# running make install will install the docset in
++# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
++# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
++# genXcode/_index.html for more information.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++GENERATE_DOCSET = NO
++
++# This tag determines the name of the docset feed. A documentation feed provides
++# an umbrella under which multiple documentation sets from a single provider
++# (such as a company or product suite) can be grouped.
++# The default value is: Doxygen generated docs.
++# This tag requires that the tag GENERATE_DOCSET is set to YES.
++
++DOCSET_FEEDNAME = "Doxygen generated docs"
++
++# This tag specifies a string that should uniquely identify the documentation
++# set bundle. This should be a reverse domain-name style string, e.g.
++# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
++# The default value is: org.doxygen.Project.
++# This tag requires that the tag GENERATE_DOCSET is set to YES.
++
++DOCSET_BUNDLE_ID = org.doxygen.Project
++
++# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
++# the documentation publisher. This should be a reverse domain-name style
++# string, e.g. com.mycompany.MyDocSet.documentation.
++# The default value is: org.doxygen.Publisher.
++# This tag requires that the tag GENERATE_DOCSET is set to YES.
++
++DOCSET_PUBLISHER_ID = org.doxygen.Publisher
++
++# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
++# The default value is: Publisher.
++# This tag requires that the tag GENERATE_DOCSET is set to YES.
++
++DOCSET_PUBLISHER_NAME = Publisher
++
++# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
++# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
++# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
++# (see:
++# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
++#
++# The HTML Help Workshop contains a compiler that can convert all HTML output
++# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
++# files are now used as the Windows 98 help format, and will replace the old
++# Windows help format (.hlp) on all Windows platforms in the future. Compressed
++# HTML files also contain an index, a table of contents, and you can search for
++# words in the documentation. The HTML workshop also contains a viewer for
++# compressed HTML files.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++GENERATE_HTMLHELP = NO
++
++# The CHM_FILE tag can be used to specify the file name of the resulting .chm
++# file. You can add a path in front of the file if the result should not be
++# written to the html output directory.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++CHM_FILE =
++
++# The HHC_LOCATION tag can be used to specify the location (absolute path
++# including file name) of the HTML help compiler (hhc.exe). If non-empty,
++# doxygen will try to run the HTML help compiler on the generated index.hhp.
++# The file has to be specified with full path.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++HHC_LOCATION =
++
++# The GENERATE_CHI flag controls if a separate .chi index file is generated
++# (YES) or that it should be included in the main .chm file (NO).
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++GENERATE_CHI = NO
++
++# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
++# and project file content.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++CHM_INDEX_ENCODING =
++
++# The BINARY_TOC flag controls whether a binary table of contents is generated
++# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
++# enables the Previous and Next buttons.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++BINARY_TOC = NO
++
++# The TOC_EXPAND flag can be set to YES to add extra items for group members to
++# the table of contents of the HTML help documentation and to the tree view.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
++
++TOC_EXPAND = NO
++
++# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
++# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
++# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
++# (.qch) of the generated HTML documentation.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++GENERATE_QHP = NO
++
++# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
++# the file name of the resulting .qch file. The path specified is relative to
++# the HTML output folder.
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QCH_FILE =
++
++# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
++# Project output. For more information please see Qt Help Project / Namespace
++# (see:
++# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
++# The default value is: org.doxygen.Project.
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHP_NAMESPACE =
++
++# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
++# Help Project output. For more information please see Qt Help Project / Virtual
++# Folders (see:
++# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
++# The default value is: doc.
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHP_VIRTUAL_FOLDER = doc
++
++# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
++# filter to add. For more information please see Qt Help Project / Custom
++# Filters (see:
++# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHP_CUST_FILTER_NAME =
++
++# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
++# custom filter to add. For more information please see Qt Help Project / Custom
++# Filters (see:
++# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHP_CUST_FILTER_ATTRS =
++
++# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
++# project's filter section matches. Qt Help Project / Filter Attributes (see:
++# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHP_SECT_FILTER_ATTRS =
++
++# The QHG_LOCATION tag can be used to specify the location (absolute path
++# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
++# run qhelpgenerator on the generated .qhp file.
++# This tag requires that the tag GENERATE_QHP is set to YES.
++
++QHG_LOCATION =
++
++# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
++# generated, together with the HTML files, they form an Eclipse help plugin. To
++# install this plugin and make it available under the help contents menu in
++# Eclipse, the contents of the directory containing the HTML and XML files needs
++# to be copied into the plugins directory of eclipse. The name of the directory
++# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
++# After copying Eclipse needs to be restarted before the help appears.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++GENERATE_ECLIPSEHELP = NO
++
++# A unique identifier for the Eclipse help plugin. When installing the plugin
++# the directory name containing the HTML and XML files should also have this
++# name. Each documentation set should have its own identifier.
++# The default value is: org.doxygen.Project.
++# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
++
++ECLIPSE_DOC_ID = org.doxygen.Project
++
++# If you want full control over the layout of the generated HTML pages it might
++# be necessary to disable the index and replace it with your own. The
++# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
++# of each HTML page. A value of NO enables the index and the value YES disables
++# it. Since the tabs in the index contain the same information as the navigation
++# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++DISABLE_INDEX = NO
++
++# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
++# structure should be generated to display hierarchical information. If the tag
++# value is set to YES, a side panel will be generated containing a tree-like
++# index structure (just like the one that is generated for HTML Help). For this
++# to work a browser that supports JavaScript, DHTML, CSS and frames is required
++# (i.e. any modern browser). Windows users are probably better off using the
++# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
++# further fine-tune the look of the index. As an example, the default style
++# sheet generated by doxygen has an example that shows how to put an image at
++# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
++# the same information as the tab index, you could consider setting
++# DISABLE_INDEX to YES when enabling this option.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++GENERATE_TREEVIEW = YES
++
++# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
++# doxygen will group on one line in the generated HTML documentation.
++#
++# Note that a value of 0 will completely suppress the enum values from appearing
++# in the overview section.
++# Minimum value: 0, maximum value: 20, default value: 4.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++ENUM_VALUES_PER_LINE = 4
++
++# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
++# to set the initial width (in pixels) of the frame in which the tree is shown.
++# Minimum value: 0, maximum value: 1500, default value: 250.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++TREEVIEW_WIDTH = 180
++
++# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
++# external symbols imported via tag files in a separate window.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++EXT_LINKS_IN_WINDOW = NO
++
++# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
++# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
++# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
++# the HTML output. These images will generally look nicer at scaled resolutions.
++# Possible values are: png (the default) and svg (looks nicer but requires the
++# pdf2svg or inkscape tool).
++# The default value is: png.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++HTML_FORMULA_FORMAT = png
++
++# Use this tag to change the font size of LaTeX formulas included as images in
++# the HTML documentation. When you change the font size after a successful
++# doxygen run you need to manually remove any form_*.png images from the HTML
++# output directory to force them to be regenerated.
++# Minimum value: 8, maximum value: 50, default value: 10.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++FORMULA_FONTSIZE = 10
++
++# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
++# generated for formulas are transparent PNGs. Transparent PNGs are not
++# supported properly for IE 6.0, but are supported on all modern browsers.
++#
++# Note that when changing this option you need to delete any form_*.png files in
++# the HTML output directory before the changes have effect.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++FORMULA_TRANSPARENT = YES
++
++# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
++# to create new LaTeX commands to be used in formulas as building blocks. See
++# the section "Including formulas" for details.
++
++FORMULA_MACROFILE =
++
++# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
++# https://www.mathjax.org) which uses client side JavaScript for the rendering
++# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
++# installed or if you want to formulas look prettier in the HTML output. When
++# enabled you may also need to install MathJax separately and configure the path
++# to it using the MATHJAX_RELPATH option.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++USE_MATHJAX = NO
++
++# When MathJax is enabled you can set the default output format to be used for
++# the MathJax output. See the MathJax site (see:
++# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
++# Possible values are: HTML-CSS (which is slower, but has the best
++# compatibility), NativeMML (i.e. MathML) and SVG.
++# The default value is: HTML-CSS.
++# This tag requires that the tag USE_MATHJAX is set to YES.
++
++MATHJAX_FORMAT = HTML-CSS
++
++# When MathJax is enabled you need to specify the location relative to the HTML
++# output directory using the MATHJAX_RELPATH option. The destination directory
++# should contain the MathJax.js script. For instance, if the mathjax directory
++# is located at the same level as the HTML output directory, then
++# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
++# Content Delivery Network so you can quickly see the result without installing
++# MathJax. However, it is strongly recommended to install a local copy of
++# MathJax from https://www.mathjax.org before deployment.
++# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
++# This tag requires that the tag USE_MATHJAX is set to YES.
++
++MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
++
++# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
++# extension names that should be enabled during MathJax rendering. For example
++# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
++# This tag requires that the tag USE_MATHJAX is set to YES.
++
++MATHJAX_EXTENSIONS =
++
++# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
++# of code that will be used on startup of the MathJax code. See the MathJax site
++# (see:
++# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
++# example see the documentation.
++# This tag requires that the tag USE_MATHJAX is set to YES.
++
++MATHJAX_CODEFILE =
++
++# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
++# the HTML output. The underlying search engine uses javascript and DHTML and
++# should work on any modern browser. Note that when using HTML help
++# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
++# there is already a search function so this one should typically be disabled.
++# For large projects the javascript based search engine can be slow, then
++# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
++# search using the keyboard; to jump to the search box use <access key> + S
++# (what the <access key> is depends on the OS and browser, but it is typically
++# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
++# key> to jump into the search results window, the results can be navigated
++# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
++# the search. The filter options can be selected when the cursor is inside the
++# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
++# to select a filter and <Enter> or <escape> to activate or cancel the filter
++# option.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_HTML is set to YES.
++
++SEARCHENGINE = NO
++
++# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
++# implemented using a web server instead of a web client using JavaScript. There
++# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
++# setting. When disabled, doxygen will generate a PHP script for searching and
++# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
++# and searching needs to be provided by external tools. See the section
++# "External Indexing and Searching" for details.
++# The default value is: NO.
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++SERVER_BASED_SEARCH = NO
++
++# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
++# script for searching. Instead the search results are written to an XML file
++# which needs to be processed by an external indexer. Doxygen will invoke an
++# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
++# search results.
++#
++# Doxygen ships with an example indexer (doxyindexer) and search engine
++# (doxysearch.cgi) which are based on the open source search engine library
++# Xapian (see:
++# https://xapian.org/).
++#
++# See the section "External Indexing and Searching" for details.
++# The default value is: NO.
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++EXTERNAL_SEARCH = NO
++
++# The SEARCHENGINE_URL should point to a search engine hosted by a web server
++# which will return the search results when EXTERNAL_SEARCH is enabled.
++#
++# Doxygen ships with an example indexer (doxyindexer) and search engine
++# (doxysearch.cgi) which are based on the open source search engine library
++# Xapian (see:
++# https://xapian.org/). See the section "External Indexing and Searching" for
++# details.
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++SEARCHENGINE_URL =
++
++# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
++# search data is written to a file for indexing by an external tool. With the
++# SEARCHDATA_FILE tag the name of this file can be specified.
++# The default file is: searchdata.xml.
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++SEARCHDATA_FILE = searchdata.xml
++
++# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
++# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
++# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
++# projects and redirect the results back to the right project.
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++EXTERNAL_SEARCH_ID =
++
++# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
++# projects other than the one defined by this configuration file, but that are
++# all added to the same external search index. Each project needs to have a
++# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
++# to a relative location where the documentation can be found. The format is:
++# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
++# This tag requires that the tag SEARCHENGINE is set to YES.
++
++EXTRA_SEARCH_MAPPINGS =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
++# The default value is: YES.
++
++GENERATE_LATEX = NO
++
++# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
++# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
++# it.
++# The default directory is: latex.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_OUTPUT = latex
++
++# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
++# invoked.
++#
++# Note that when not enabling USE_PDFLATEX the default is latex when enabling
++# USE_PDFLATEX the default is pdflatex and when in the later case latex is
++# chosen this is overwritten by pdflatex. For specific output languages the
++# default can have been set differently, this depends on the implementation of
++# the output language.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_CMD_NAME = latex
++
++# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
++# index for LaTeX.
++# Note: This tag is used in the Makefile / make.bat.
++# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
++# (.tex).
++# The default file is: makeindex.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++MAKEINDEX_CMD_NAME = makeindex
++
++# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
++# generate index for LaTeX. In case there is no backslash (\) as first character
++# it will be automatically added in the LaTeX code.
++# Note: This tag is used in the generated output file (.tex).
++# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
++# The default value is: makeindex.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_MAKEINDEX_CMD = makeindex
++
++# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
++# documents. This may be useful for small projects and may help to save some
++# trees in general.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++COMPACT_LATEX = NO
++
++# The PAPER_TYPE tag can be used to set the paper type that is used by the
++# printer.
++# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
++# 14 inches) and executive (7.25 x 10.5 inches).
++# The default value is: a4.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++PAPER_TYPE = a4
++
++# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
++# that should be included in the LaTeX output. The package can be specified just
++# by its name or with the correct syntax as to be used with the LaTeX
++# \usepackage command. To get the times font for instance you can specify :
++# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
++# To use the option intlimits with the amsmath package you can specify:
++# EXTRA_PACKAGES=[intlimits]{amsmath}
++# If left blank no extra packages will be included.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++EXTRA_PACKAGES =
++
++# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
++# generated LaTeX document. The header should contain everything until the first
++# chapter. If it is left blank doxygen will generate a standard header. See
++# section "Doxygen usage" for information on how to let doxygen write the
++# default header to a separate file.
++#
++# Note: Only use a user-defined header if you know what you are doing! The
++# following commands have a special meaning inside the header: $title,
++# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
++# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
++# string, for the replacement values of the other commands the user is referred
++# to HTML_HEADER.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_HEADER =
++
++# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
++# generated LaTeX document. The footer should contain everything after the last
++# chapter. If it is left blank doxygen will generate a standard footer. See
++# LATEX_HEADER for more information on how to generate a default footer and what
++# special commands can be used inside the footer.
++#
++# Note: Only use a user-defined footer if you know what you are doing!
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_FOOTER =
++
++# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
++# LaTeX style sheets that are included after the standard style sheets created
++# by doxygen. Using this option one can overrule certain style aspects. Doxygen
++# will copy the style sheet files to the output directory.
++# Note: The order of the extra style sheet files is of importance (e.g. the last
++# style sheet in the list overrules the setting of the previous ones in the
++# list).
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_EXTRA_STYLESHEET =
++
++# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
++# other source files which should be copied to the LATEX_OUTPUT output
++# directory. Note that the files will be copied as-is; there are no commands or
++# markers available.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_EXTRA_FILES =
++
++# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
++# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
++# contain links (just like the HTML output) instead of page references. This
++# makes the output suitable for online browsing using a PDF viewer.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++PDF_HYPERLINKS = NO
++
++# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
++# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
++# files. Set this option to YES, to get a higher quality PDF documentation.
++#
++# See also section LATEX_CMD_NAME for selecting the engine.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++USE_PDFLATEX = NO
++
++# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
++# command to the generated LaTeX files. This will instruct LaTeX to keep running
++# if errors occur, instead of asking the user for help. This option is also used
++# when generating formulas in HTML.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_BATCHMODE = NO
++
++# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
++# index chapters (such as File Index, Compound Index, etc.) in the output.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_HIDE_INDICES = NO
++
++# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
++# code with syntax highlighting in the LaTeX output.
++#
++# Note that which sources are shown also depends on other settings such as
++# SOURCE_BROWSER.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_SOURCE_CODE = NO
++
++# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
++# bibliography, e.g. plainnat, or ieeetr. See
++# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
++# The default value is: plain.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_BIB_STYLE = plain
++
++# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
++# page will contain the date and time when the page was generated. Setting this
++# to NO can help when comparing the output of multiple runs.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_TIMESTAMP = NO
++
++# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
++# path from which the emoji images will be read. If a relative path is entered,
++# it will be relative to the LATEX_OUTPUT directory. If left blank the
++# LATEX_OUTPUT directory will be used.
++# This tag requires that the tag GENERATE_LATEX is set to YES.
++
++LATEX_EMOJI_DIRECTORY =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the RTF output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
++# RTF output is optimized for Word 97 and may not look too pretty with other RTF
++# readers/editors.
++# The default value is: NO.
++
++GENERATE_RTF = NO
++
++# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
++# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
++# it.
++# The default directory is: rtf.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++RTF_OUTPUT = rtf
++
++# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
++# documents. This may be useful for small projects and may help to save some
++# trees in general.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++COMPACT_RTF = NO
++
++# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
++# contain hyperlink fields. The RTF file will contain links (just like the HTML
++# output) instead of page references. This makes the output suitable for online
++# browsing using Word or some other Word compatible readers that support those
++# fields.
++#
++# Note: WordPad (write) and others do not support links.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++RTF_HYPERLINKS = NO
++
++# Load stylesheet definitions from file. Syntax is similar to doxygen's
++# configuration file, i.e. a series of assignments. You only have to provide
++# replacements, missing definitions are set to their default value.
++#
++# See also section "Doxygen usage" for information on how to generate the
++# default style sheet that doxygen normally uses.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++RTF_STYLESHEET_FILE =
++
++# Set optional variables used in the generation of an RTF document. Syntax is
++# similar to doxygen's configuration file. A template extensions file can be
++# generated using doxygen -e rtf extensionFile.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++RTF_EXTENSIONS_FILE =
++
++# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
++# with syntax highlighting in the RTF output.
++#
++# Note that which sources are shown also depends on other settings such as
++# SOURCE_BROWSER.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_RTF is set to YES.
++
++RTF_SOURCE_CODE = NO
++
++#---------------------------------------------------------------------------
++# Configuration options related to the man page output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
++# classes and files.
++# The default value is: NO.
++
++GENERATE_MAN = NO
++
++# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
++# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
++# it. A directory man3 will be created inside the directory specified by
++# MAN_OUTPUT.
++# The default directory is: man.
++# This tag requires that the tag GENERATE_MAN is set to YES.
++
++MAN_OUTPUT = man
++
++# The MAN_EXTENSION tag determines the extension that is added to the generated
++# man pages. In case the manual section does not start with a number, the number
++# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
++# optional.
++# The default value is: .3.
++# This tag requires that the tag GENERATE_MAN is set to YES.
++
++MAN_EXTENSION = .3
++
++# The MAN_SUBDIR tag determines the name of the directory created within
++# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
++# MAN_EXTENSION with the initial . removed.
++# This tag requires that the tag GENERATE_MAN is set to YES.
++
++MAN_SUBDIR =
++
++# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
++# will generate one additional man file for each entity documented in the real
++# man page(s). These additional files only source the real man page, but without
++# them the man command would be unable to find the correct page.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_MAN is set to YES.
++
++MAN_LINKS = NO
++
++#---------------------------------------------------------------------------
++# Configuration options related to the XML output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
++# captures the structure of the code including all documentation.
++# The default value is: NO.
++
++GENERATE_XML = NO
++
++# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
++# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
++# it.
++# The default directory is: xml.
++# This tag requires that the tag GENERATE_XML is set to YES.
++
++XML_OUTPUT = xml
++
++# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
++# listings (including syntax highlighting and cross-referencing information) to
++# the XML output. Note that enabling this will significantly increase the size
++# of the XML output.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_XML is set to YES.
++
++XML_PROGRAMLISTING = NO
++
++# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
++# namespace members in file scope as well, matching the HTML output.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_XML is set to YES.
++
++XML_NS_MEMB_FILE_SCOPE = NO
++
++#---------------------------------------------------------------------------
++# Configuration options related to the DOCBOOK output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
++# that can be used to generate PDF.
++# The default value is: NO.
++
++GENERATE_DOCBOOK = NO
++
++# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
++# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
++# front of it.
++# The default directory is: docbook.
++# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
++
++DOCBOOK_OUTPUT = docbook
++
++# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
++# program listings (including syntax highlighting and cross-referencing
++# information) to the DOCBOOK output. Note that enabling this will significantly
++# increase the size of the DOCBOOK output.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
++
++DOCBOOK_PROGRAMLISTING = NO
++
++#---------------------------------------------------------------------------
++# Configuration options for the AutoGen Definitions output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
++# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
++# the structure of the code including all documentation. Note that this feature
++# is still experimental and incomplete at the moment.
++# The default value is: NO.
++
++GENERATE_AUTOGEN_DEF = NO
++
++#---------------------------------------------------------------------------
++# Configuration options related to the Perl module output
++#---------------------------------------------------------------------------
++
++# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
++# file that captures the structure of the code including all documentation.
++#
++# Note that this feature is still experimental and incomplete at the moment.
++# The default value is: NO.
++
++GENERATE_PERLMOD = NO
++
++# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
++# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
++# output from the Perl module output.
++# The default value is: NO.
++# This tag requires that the tag GENERATE_PERLMOD is set to YES.
++
++PERLMOD_LATEX = NO
++
++# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
++# formatted so it can be parsed by a human reader. This is useful if you want to
++# understand what is going on. On the other hand, if this tag is set to NO, the
++# size of the Perl module output will be much smaller and Perl will parse it
++# just the same.
++# The default value is: YES.
++# This tag requires that the tag GENERATE_PERLMOD is set to YES.
++
++PERLMOD_PRETTY = YES
++
++# The names of the make variables in the generated doxyrules.make file are
++# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
++# so different doxyrules.make files included by the same Makefile don't
++# overwrite each other's variables.
++# This tag requires that the tag GENERATE_PERLMOD is set to YES.
++
++PERLMOD_MAKEVAR_PREFIX =
++
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++
++# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
++# C-preprocessor directives found in the sources and include files.
++# The default value is: YES.
++
++ENABLE_PREPROCESSING = YES
++
++# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
++# in the source code. If set to NO, only conditional compilation will be
++# performed. Macro expansion can be done in a controlled way by setting
++# EXPAND_ONLY_PREDEF to YES.
++# The default value is: NO.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++MACRO_EXPANSION = YES
++
++# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
++# the macro expansion is limited to the macros specified with the PREDEFINED and
++# EXPAND_AS_DEFINED tags.
++# The default value is: NO.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++EXPAND_ONLY_PREDEF = NO
++
++# If the SEARCH_INCLUDES tag is set to YES, the include files in the
++# INCLUDE_PATH will be searched if a #include is found.
++# The default value is: YES.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++SEARCH_INCLUDES = YES
++
++# The INCLUDE_PATH tag can be used to specify one or more directories that
++# contain include files that are not input files but should be processed by the
++# preprocessor.
++# This tag requires that the tag SEARCH_INCLUDES is set to YES.
++
++INCLUDE_PATH =
++
++# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
++# patterns (like *.h and *.hpp) to filter out the header-files in the
++# directories. If left blank, the patterns specified with FILE_PATTERNS will be
++# used.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++INCLUDE_FILE_PATTERNS =
++
++# The PREDEFINED tag can be used to specify one or more macro names that are
++# defined before the preprocessor is started (similar to the -D option of e.g.
++# gcc). The argument of the tag is a list of macros of the form: name or
++# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
++# is assumed. To prevent a macro definition from being undefined via #undef or
++# recursively expanded use the := operator instead of the = operator.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++PREDEFINED =
++
++# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
++# tag can be used to specify a list of macro names that should be expanded. The
++# macro definition that is found in the sources will be used. Use the PREDEFINED
++# tag if you want to use a different macro definition that overrules the
++# definition found in the source code.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++EXPAND_AS_DEFINED =
++
++# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
++# remove all references to function-like macros that are alone on a line, have
++# an all uppercase name, and do not end with a semicolon. Such function macros
++# are typically used for boiler-plate code, and will confuse the parser if not
++# removed.
++# The default value is: YES.
++# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
++
++SKIP_FUNCTION_MACROS = YES
++
++#---------------------------------------------------------------------------
++# Configuration options related to external references
++#---------------------------------------------------------------------------
++
++# The TAGFILES tag can be used to specify one or more tag files. For each tag
++# file the location of the external documentation should be added. The format of
++# a tag file without this location is as follows:
++# TAGFILES = file1 file2 ...
++# Adding location for the tag files is done as follows:
++# TAGFILES = file1=loc1 "file2 = loc2" ...
++# where loc1 and loc2 can be relative or absolute paths or URLs. See the
++# section "Linking to external documentation" for more information about the use
++# of tag files.
++# Note: Each tag file must have a unique name (where the name does NOT include
++# the path). If a tag file is not located in the directory in which doxygen is
++# run, you must also specify the path to the tagfile here.
++
++TAGFILES =
++
++# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
++# tag file that is based on the input files it reads. See section "Linking to
++# external documentation" for more information about the usage of tag files.
++
++GENERATE_TAGFILE =
++
++# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
++# the class index. If set to NO, only the inherited external classes will be
++# listed.
++# The default value is: NO.
++
++ALLEXTERNALS = NO
++
++# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
++# in the modules index. If set to NO, only the current project's groups will be
++# listed.
++# The default value is: YES.
++
++EXTERNAL_GROUPS = YES
++
++# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
++# the related pages index. If set to NO, only the current project's pages will
++# be listed.
++# The default value is: YES.
++
++EXTERNAL_PAGES = YES
++
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++
++# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
++# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
++# NO turns the diagrams off. Note that this option also works with HAVE_DOT
++# disabled, but it is recommended to install and use dot, since it yields more
++# powerful graphs.
++# The default value is: YES.
++
++CLASS_DIAGRAMS = YES
++
++# You can include diagrams made with dia in doxygen documentation. Doxygen will
++# then run dia to produce the diagram and insert it in the documentation. The
++# DIA_PATH tag allows you to specify the directory where the dia binary resides.
++# If left empty dia is assumed to be found in the default search path.
++
++DIA_PATH =
++
++# If set to YES the inheritance and collaboration graphs will hide inheritance
++# and usage relations if the target is undocumented or is not a class.
++# The default value is: YES.
++
++HIDE_UNDOC_RELATIONS = YES
++
++# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
++# available from the path. This tool is part of Graphviz (see:
++# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
++# Bell Labs. The other options in this section have no effect if this option is
++# set to NO
++# The default value is: NO.
++
++HAVE_DOT = YES
++
++# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
++# to run in parallel. When set to 0 doxygen will base this on the number of
++# processors available in the system. You can set it explicitly to a value
++# larger than 0 to get control over the balance between CPU load and processing
++# speed.
++# Minimum value: 0, maximum value: 32, default value: 0.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_NUM_THREADS = 0
++
++# When you want a differently looking font in the dot files that doxygen
++# generates you can specify the font name using DOT_FONTNAME. You need to make
++# sure dot is able to find the font, which can be done by putting it in a
++# standard location or by setting the DOTFONTPATH environment variable or by
++# setting DOT_FONTPATH to the directory containing the font.
++# The default value is: Helvetica.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_FONTNAME = Helvetica
++
++# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
++# dot graphs.
++# Minimum value: 4, maximum value: 24, default value: 10.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_FONTSIZE = 10
++
++# By default doxygen will tell dot to use the default font as specified with
++# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
++# the path where dot can find it using this tag.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_FONTPATH =
++
++# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
++# each documented class showing the direct and indirect inheritance relations.
++# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++CLASS_GRAPH = YES
++
++# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
++# graph for each documented class showing the direct and indirect implementation
++# dependencies (inheritance, containment, and class references variables) of the
++# class with other documented classes.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++COLLABORATION_GRAPH = NO
++
++# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
++# groups, showing the direct groups dependencies.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++GROUP_GRAPHS = YES
++
++# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
++# collaboration diagrams in a style similar to the OMG's Unified Modeling
++# Language.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++UML_LOOK = NO
++
++# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
++# class node. If there are many fields or methods and many nodes the graph may
++# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
++# number of items for each type to make the size more manageable. Set this to 0
++# for no limit. Note that the threshold may be exceeded by 50% before the limit
++# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
++# but if the number exceeds 15, the total amount of fields shown is limited to
++# 10.
++# Minimum value: 0, maximum value: 100, default value: 10.
++# This tag requires that the tag UML_LOOK is set to YES.
++
++UML_LIMIT_NUM_FIELDS = 10
++
++# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
++# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
++# tag is set to YES, doxygen will add type and arguments for attributes and
++# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
++# will not generate fields with class member information in the UML graphs. The
++# class diagrams will look similar to the default class diagrams but using UML
++# notation for the relationships.
++# Possible values are: NO, YES and NONE.
++# The default value is: NO.
++# This tag requires that the tag UML_LOOK is set to YES.
++
++DOT_UML_DETAILS = NO
++
++# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
++# to display on a single line. If the actual line length exceeds this threshold
++# significantly it will wrapped across multiple lines. Some heuristics are apply
++# to avoid ugly line breaks.
++# Minimum value: 0, maximum value: 1000, default value: 17.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_WRAP_THRESHOLD = 17
++
++# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
++# collaboration graphs will show the relations between templates and their
++# instances.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++TEMPLATE_RELATIONS = NO
++
++# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
++# YES then doxygen will generate a graph for each documented file showing the
++# direct and indirect include dependencies of the file with other documented
++# files.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++INCLUDE_GRAPH = YES
++
++# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
++# set to YES then doxygen will generate a graph for each documented file showing
++# the direct and indirect include dependencies of the file with other documented
++# files.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++INCLUDED_BY_GRAPH = YES
++
++# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
++# dependency graph for every global function or class method.
++#
++# Note that enabling this option will significantly increase the time of a run.
++# So in most cases it will be better to enable call graphs for selected
++# functions only using the \callgraph command. Disabling a call graph can be
++# accomplished by means of the command \hidecallgraph.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++CALL_GRAPH = YES
++
++# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
++# dependency graph for every global function or class method.
++#
++# Note that enabling this option will significantly increase the time of a run.
++# So in most cases it will be better to enable caller graphs for selected
++# functions only using the \callergraph command. Disabling a caller graph can be
++# accomplished by means of the command \hidecallergraph.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++CALLER_GRAPH = NO
++
++# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
++# hierarchy of all classes instead of a textual one.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++GRAPHICAL_HIERARCHY = YES
++
++# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
++# dependencies a directory has on other directories in a graphical way. The
++# dependency relations are determined by the #include relations between the
++# files in the directories.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DIRECTORY_GRAPH = YES
++
++# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
++# generated by dot. For an explanation of the image formats see the section
++# output formats in the documentation of the dot tool (Graphviz (see:
++# http://www.graphviz.org/)).
++# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
++# to make the SVG files visible in IE 9+ (other browsers do not have this
++# requirement).
++# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
++# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
++# png:gdiplus:gdiplus.
++# The default value is: png.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_IMAGE_FORMAT = png
++
++# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
++# enable generation of interactive SVG images that allow zooming and panning.
++#
++# Note that this requires a modern browser other than Internet Explorer. Tested
++# and working are Firefox, Chrome, Safari, and Opera.
++# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
++# the SVG files visible. Older versions of IE do not have SVG support.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++INTERACTIVE_SVG = NO
++
++# The DOT_PATH tag can be used to specify the path where the dot tool can be
++# found. If left blank, it is assumed the dot tool can be found in the path.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_PATH =
++
++# The DOTFILE_DIRS tag can be used to specify one or more directories that
++# contain dot files that are included in the documentation (see the \dotfile
++# command).
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOTFILE_DIRS =
++
++# The MSCFILE_DIRS tag can be used to specify one or more directories that
++# contain msc files that are included in the documentation (see the \mscfile
++# command).
++
++MSCFILE_DIRS =
++
++# The DIAFILE_DIRS tag can be used to specify one or more directories that
++# contain dia files that are included in the documentation (see the \diafile
++# command).
++
++DIAFILE_DIRS =
++
++# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
++# path where java can find the plantuml.jar file. If left blank, it is assumed
++# PlantUML is not used or called during a preprocessing step. Doxygen will
++# generate a warning when it encounters a \startuml command in this case and
++# will not generate output for the diagram.
++
++PLANTUML_JAR_PATH =
++
++# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
++# configuration file for plantuml.
++
++PLANTUML_CFG_FILE =
++
++# When using plantuml, the specified paths are searched for files specified by
++# the !include statement in a plantuml block.
++
++PLANTUML_INCLUDE_PATH =
++
++# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
++# that will be shown in the graph. If the number of nodes in a graph becomes
++# larger than this value, doxygen will truncate the graph, which is visualized
++# by representing a node as a red box. Note that doxygen if the number of direct
++# children of the root node in a graph is already larger than
++# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
++# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
++# Minimum value: 0, maximum value: 10000, default value: 50.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_GRAPH_MAX_NODES = 200
++
++# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
++# generated by dot. A depth value of 3 means that only nodes reachable from the
++# root by following a path via at most 3 edges will be shown. Nodes that lay
++# further from the root node will be omitted. Note that setting this option to 1
++# or 2 may greatly reduce the computation time needed for large code bases. Also
++# note that the size of a graph can be further restricted by
++# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
++# Minimum value: 0, maximum value: 1000, default value: 0.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++MAX_DOT_GRAPH_DEPTH = 0
++
++# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
++# background. This is disabled by default, because dot on Windows does not seem
++# to support this out of the box.
++#
++# Warning: Depending on the platform used, enabling this option may lead to
++# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
++# read).
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_TRANSPARENT = NO
++
++# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
++# files in one run (i.e. multiple -o and -T options on the command line). This
++# makes dot run faster, but since only newer versions of dot (>1.8.10) support
++# this, this feature is disabled by default.
++# The default value is: NO.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++DOT_MULTI_TARGETS = NO
++
++# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
++# explaining the meaning of the various boxes and arrows in the dot generated
++# graphs.
++# The default value is: YES.
++# This tag requires that the tag HAVE_DOT is set to YES.
++
++GENERATE_LEGEND = YES
++
++# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
++# files that are used to generate the various graphs.
++#
++# Note: This setting is not only used for dot files but also for msc and
++# plantuml temporary files.
++# The default value is: YES.
++
++DOT_CLEANUP = YES
+diff --git a/src/hooks/dhcp/ping_check/Makefile.am b/src/hooks/dhcp/ping_check/Makefile.am
+new file mode 100644
+index 0000000000..a7ea17f400
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/Makefile.am
+@@ -0,0 +1,104 @@
++SUBDIRS = . libloadtests tests
++
++AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
++AM_CPPFLAGS += $(BOOST_INCLUDES) $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
++AM_CXXFLAGS = $(KEA_CXXFLAGS)
++
++# Ensure that the message file and doxygen file is included in the distribution
++EXTRA_DIST = ping_check_messages.mes
++
++CLEANFILES = *.gcno *.gcda
++
++# convenience archive
++
++noinst_LTLIBRARIES = libping_check.la
++
++libping_check_la_SOURCES = ping_check_callouts.cc
++libping_check_la_SOURCES += ping_check_log.cc ping_check_log.h
++libping_check_la_SOURCES += ping_check_messages.cc ping_check_messages.h
++libping_check_la_SOURCES += icmp_endpoint.h icmp_socket.h
++libping_check_la_SOURCES += ping_context.cc ping_context.h
++libping_check_la_SOURCES += ping_context_store.cc ping_context_store.h
++libping_check_la_SOURCES += icmp_msg.h icmp_msg.cc
++libping_check_la_SOURCES += ping_channel.cc ping_channel.h
++libping_check_la_SOURCES += ping_check_mgr.cc ping_check_mgr.h
++libping_check_la_SOURCES += ping_check_config.cc ping_check_config.h
++libping_check_la_SOURCES += config_cache.cc config_cache.h
++libping_check_la_SOURCES += version.cc
++
++libping_check_la_CXXFLAGS = $(AM_CXXFLAGS)
++libping_check_la_CPPFLAGS = $(AM_CPPFLAGS)
++
++# install the shared object into $(libdir)/kea/hooks
++lib_hooksdir = $(libdir)/kea/hooks
++lib_hooks_LTLIBRARIES = libdhcp_ping_check.la
++
++libdhcp_ping_check_la_SOURCES =
++libdhcp_ping_check_la_LDFLAGS = $(AM_LDFLAGS)
++libdhcp_ping_check_la_LDFLAGS += -avoid-version -export-dynamic -module
++libdhcp_ping_check_la_LIBADD = libping_check.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/http/libkea-http.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
++libdhcp_ping_check_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
++libdhcp_ping_check_la_LIBADD += $(LOG4CPLUS_LIBS)
++libdhcp_ping_check_la_LIBADD += $(CRYPTO_LIBS)
++libdhcp_ping_check_la_LIBADD += $(BOOST_LIBS)
++
++# Doxygen documentation
++EXTRA_DIST += ping_check.dox Doxyfile
++
++devel:
++ mkdir -p html
++ (cat Doxyfile; echo PROJECT_NUMBER=$(PACKAGE_VERSION)) | doxygen - > html/doxygen.log 2> html/doxygen-error.log
++ echo `grep -i ": warning:" html/doxygen-error.log | wc -l` warnings/errors detected.
++
++clean-local:
++ rm -rf html
++
++# If we want to get rid of all generated messages files, we need to use
++# make maintainer-clean. The proper way to introduce custom commands for
++# that operation is to define maintainer-clean-local target. However,
++# make maintainer-clean also removes Makefile, so running configure script
++# is required. To make it easy to rebuild messages without going through
++# reconfigure, a new target messages-clean has been added.
++maintainer-clean-local:
++ rm -f ping_check_messages.h ping_check_messages.cc
++
++# To regenerate messages files, one can do:
++#
++# make messages-clean
++# make messages
++#
++# This is needed only when a .mes file is modified.
++messages-clean: maintainer-clean-local
++
++if GENERATE_MESSAGES
++
++# Define rule to build logging source files from message file
++messages: ping_check_messages.h ping_check_messages.cc
++ @echo Message files regenerated
++
++ping_check_messages.h ping_check_messages.cc: ping_check_messages.mes
++ (cd $(top_srcdir); \
++ $(abs_top_builddir)/src/lib/log/compiler/kea-msg-compiler src/hooks/dhcp/ping_check/ping_check_messages.mes)
++
++else
++
++messages ping_check_messages.h ping_check_messages.cc:
++ @echo Messages generation disabled. Configure with --enable-generate-messages to enable it.
++
++endif
+diff --git a/src/hooks/dhcp/ping_check/config_cache.cc b/src/hooks/dhcp/ping_check/config_cache.cc
+new file mode 100644
+index 0000000000..9a8f9dd4bb
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/config_cache.cc
+@@ -0,0 +1,107 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <config_cache.h>
++#include <util/multi_threading_mgr.h>
++
++using namespace isc;
++using namespace isc::data;
++using namespace isc::dhcp;
++using namespace isc::util;
++using namespace std;
++
++namespace isc {
++namespace ping_check {
++
++PingCheckConfigPtr&
++ConfigCache::getGlobalConfig() {
++ return (global_config_);
++}
++
++void
++ConfigCache::setGlobalConfig(PingCheckConfigPtr& config) {
++ if (!config) {
++ isc_throw(BadValue, "ConfigCache - global config cannot be empty");
++ }
++
++ global_config_ = config;
++}
++
++bool
++ConfigCache::findConfig(const SubnetID& subnet_id, PingCheckConfigPtr& config) {
++ MultiThreadingLock lock(*mutex_);
++ return (findConfigInternal(subnet_id, config));
++}
++
++bool
++ConfigCache::findConfigInternal(const SubnetID& subnet_id, PingCheckConfigPtr& config) const {
++ auto it = configs_.find(subnet_id);
++ if (it != configs_.end()) {
++ config = it->second;
++ return (true);
++ }
++
++ config = PingCheckConfigPtr();
++ return (false);
++}
++
++PingCheckConfigPtr
++ConfigCache::parseAndCacheConfig(const SubnetID& subnet_id, ConstElementPtr& user_context) {
++ PingCheckConfigPtr config;
++ if (user_context) {
++ ConstElementPtr ping_check_params = user_context->get("ping-check");
++ if (ping_check_params) {
++ // Copy construct from global to start with.
++ config.reset(new PingCheckConfig(*getGlobalConfig()));
++
++ // Now parse in subnet-specific values. This may throw a DhcpConfigError but
++ // that's OK, dealt with by the caller.
++ try {
++ config->parse(ping_check_params);
++ } catch (...) {
++ throw;
++ }
++ }
++ }
++
++ // Cache the config. We allow empty configs so higher precedence scopes may
++ // override lower precedence scopes.
++ cacheConfig(subnet_id, config);
++ return (config);
++}
++
++void
++ConfigCache::cacheConfig(const SubnetID& subnet_id, PingCheckConfigPtr& config) {
++ MultiThreadingLock lock(*mutex_);
++ configs_[subnet_id] = config;
++}
++
++void
++ConfigCache::flush() {
++ MultiThreadingLock lock(*mutex_);
++ // Discard the contents.
++ configs_.clear();
++
++ // We use modification time to remember the last time we flushed.
++ updateModificationTime();
++}
++
++size_t
++ConfigCache::size() {
++ MultiThreadingLock lock(*mutex_);
++ return (configs_.size());
++}
++
++boost::posix_time::ptime
++ConfigCache::getLastFlushTime() {
++ MultiThreadingLock lock(*mutex_);
++ return (BaseStampedElement::getModificationTime());
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/config_cache.h b/src/hooks/dhcp/ping_check/config_cache.h
+new file mode 100644
+index 0000000000..b69cf6f124
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/config_cache.h
+@@ -0,0 +1,146 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef CONFIG_CACHE_H
++#define CONFIG_CACHE_H
++
++#include <ping_check_config.h>
++#include <cc/base_stamped_element.h>
++#include <cc/data.h>
++#include <dhcpsrv/subnet.h>
++
++#include <map>
++#include <mutex>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief ConfigCache stores ping check config per subnet
++///
++/// The intent is parse subnet ping-check parameters from its user-context
++/// as few times as possible rather than on every ping check request, while
++/// also allowing for run time updates via config back end or subnet cmds.
++///
++/// For every subnet we store:
++///
++/// -# subnet id
++/// -# PingCheckConfig pointer
++/// where:
++/// - empty config pointer means that subnet does not specify ping check config
++/// - non-empty means subnet specifies at least some ping check parameters
++///
++/// Each time we clear the cache we update the modification time.
++///
++/// When presented with a subnet:
++///
++/// 1. no cache entry:
++/// cache it
++///
++/// 2. entry exists:
++/// subnet mod time >= last flush
++/// cache is stale flush it
++/// cache it
++///
++/// subnet mod time < last flush
++/// use it
++///
++class ConfigCache : public data::BaseStampedElement {
++public:
++ /// @brief Constructor
++ ConfigCache() : configs_(), global_config_(new PingCheckConfig()), mutex_(new std::mutex) {
++ }
++
++ /// @brief Destructor
++ virtual ~ConfigCache() = default;
++
++ /// @brief Get the config for a given subnet.
++ ///
++ /// @param subnet_id ID of the subnet for which the config is desired.
++ /// @param[out] config a reference to a pointer in which to store the
++ /// config if found. If there is no entry for the subnet, it will be set
++ /// to an empty pointer.
++ ///
++ /// @return True if an entry for subnet was found, false otherwise. This
++ /// allows callers to distinguish between unknown subnets (entries that do
++ /// not exist) and subnets that are known but do not define a config.
++ bool findConfig(const dhcp::SubnetID& subnet_id,
++ PingCheckConfigPtr& config);
++
++ /// @brief Parses a config string and caches for the given subnet.
++ ///
++ /// @param subnet_id ID of the subnet for which the config is desired.
++ /// @param user_context user-context Element map of the subnet.
++ ///
++ /// @return pointer to the parsed config.
++ /// @throw BadValue if an error occurred during config parsing.
++ PingCheckConfigPtr parseAndCacheConfig(const dhcp::SubnetID& subnet_id,
++ data::ConstElementPtr& user_context);
++
++ /// @brief Adds (or replaces) the config for a given subnet to the cache.
++ ///
++ /// @param subnet_id ID of the subnet for which the config is desired.
++ /// @param config pointer to the config to store. This may be an
++ /// empty pointer.
++ void cacheConfig(const dhcp::SubnetID& subnet_id,
++ PingCheckConfigPtr& config);
++
++ /// @brief Discards the subnet entries in the cache.
++ void flush();
++
++ /// @brief Get the number of entries in the cache.
++ ///
++ /// @return number of entries in the cache.
++ size_t size();
++
++ /// @brief Get the last time the cache was flushed.
++ ///
++ /// @return the last time the cache was flushed (or the time it was
++ /// created if it has never been flushed).
++ boost::posix_time::ptime getLastFlushTime();
++
++ /// @brief Get the global level configuration.
++ ///
++ /// @return pointer to the global configuration.
++ PingCheckConfigPtr& getGlobalConfig();
++
++ /// @brief Set the global level configuration.
++ ///
++ /// @param config configuration to store as the global configuration.
++ void setGlobalConfig(PingCheckConfigPtr& config);
++
++private:
++ /// @brief Get the config for a given subnet.
++ ///
++ /// Must be called from with a thread-safe context.
++ ///
++ /// @param subnet_id ID of the subnet for which the config is desired.
++ /// @param[out] config a reference to a pointer in which to store the
++ /// config if found. If there is no entry for the subnet, it will be set
++ /// to an empty pointer.
++ ///
++ /// @return True if an entry for subnet was found, false otherwise. This
++ /// allows callers to distinguish between unknown subnets (entries that do
++ /// not exist) and subnets that are known but do not define a config.
++ bool findConfigInternal(const dhcp::SubnetID& subnet_id,
++ PingCheckConfigPtr& config) const;
++
++ /// @brief Per subnet config cache. Note that the global config in stored
++ /// using SUBNET_ID_GLOBAL.
++ std::map<dhcp::SubnetID, PingCheckConfigPtr> configs_;
++
++ /// @brief Stores the global configuration parameters.
++ PingCheckConfigPtr global_config_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++};
++
++/// @brief Defines a shared pointer to a ConfigCache.
++typedef boost::shared_ptr<ConfigCache> ConfigCachePtr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++#endif
+diff --git a/src/hooks/dhcp/ping_check/icmp_endpoint.h b/src/hooks/dhcp/ping_check/icmp_endpoint.h
+new file mode 100644
+index 0000000000..5d047d286f
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/icmp_endpoint.h
+@@ -0,0 +1,134 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef ICMP_ENDPOINT_H
++#define ICMP_ENDPOINT_H 1
++
++#include <asiolink/io_endpoint.h>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief The @c ICMPEndpoint class is a concrete derived class of
++/// @c IOEndpoint that represents an endpoint of a ICMP packet.
++///
++/// Other notes about @c TCPEndpoint applies to this class, too.
++class ICMPEndpoint : public asiolink::IOEndpoint {
++public:
++ ///
++ /// @name Constructors and Destructor.
++ ///
++ //@{
++
++ /// @brief Default Constructor
++ ///
++ /// Creates an internal endpoint. This is expected to be set by some
++ /// external call.
++ ICMPEndpoint() :
++ asio_endpoint_placeholder_(new boost::asio::ip::icmp::endpoint()),
++ asio_endpoint_(*asio_endpoint_placeholder_)
++ {}
++
++ /// @brief Constructor from an address.
++ ///
++ /// @param address The IP address of the endpoint.
++ explicit ICMPEndpoint(const asiolink::IOAddress& address) :
++ asio_endpoint_placeholder_(
++ new boost::asio::ip::icmp::endpoint(boost::asio::ip::make_address(address.toText()), 0)),
++ asio_endpoint_(*asio_endpoint_placeholder_)
++ {}
++
++ /// @brief Copy Constructor from an ASIO ICMP endpoint.
++ ///
++ /// This constructor is designed to be an efficient wrapper for the
++ /// corresponding ASIO class, @c icmp::endpoint.
++ ///
++ /// @param asio_endpoint The ASIO representation of the ICMP endpoint.
++ explicit ICMPEndpoint(boost::asio::ip::icmp::endpoint& asio_endpoint) :
++ asio_endpoint_placeholder_(0), asio_endpoint_(asio_endpoint)
++ {}
++
++ /// @brief Constructor from a const ASIO ICMP endpoint.
++ ///
++ /// This constructor is designed to be an efficient wrapper for the
++ /// corresponding ASIO class, @c icmp::endpoint.
++ ///
++ /// @param asio_endpoint The ASIO representation of the TCP endpoint.
++ explicit ICMPEndpoint(const boost::asio::ip::icmp::endpoint& asio_endpoint) :
++ asio_endpoint_placeholder_(new boost::asio::ip::icmp::endpoint(asio_endpoint)),
++ asio_endpoint_(*asio_endpoint_placeholder_)
++ {}
++
++ /// @brief The destructor.
++ virtual ~ICMPEndpoint() { delete asio_endpoint_placeholder_; }
++ //@}
++
++ /// @brief Fetches the IP address of the endpoint.
++ ///
++ /// @return the endpoint's IP address as an IOAddress.
++ virtual asiolink::IOAddress getAddress() const {
++ return (asio_endpoint_.address());
++ }
++
++ /// @brief Fetches the IP address of the endpoint in native form.
++ ///
++ /// @return the endpoint's IP address as a struct sockaddr.
++ virtual const struct sockaddr& getSockAddr() const {
++ return (*asio_endpoint_.data());
++ }
++
++ /// @brief Fetches the IP port number of the endpoint.
++ ///
++ /// @return the endpoint's port number as a unit16_t.
++ virtual uint16_t getPort() const {
++ return (asio_endpoint_.port());
++ }
++
++ /// @brief Fetches the network protocol of the endpoint.
++ ///
++ /// @return the endpoint's protocol as a short
++ virtual short getProtocol() const {
++ return (asio_endpoint_.protocol().protocol());
++ }
++
++ /// @brief Fetches the network protocol family of the endpoint.
++ ///
++ /// @return the endpoint's protocol as a short
++ virtual short getFamily() const {
++ return (asio_endpoint_.protocol().family());
++ }
++
++ /// @brief Fetches the underlying ASIO endpoint implementation
++ ///
++ /// This is not part of the exposed IOEndpoint API but allows
++ /// direct access to the ASIO implementation of the endpoint
++ ///
++ /// @return the wrapped ASIO endpoint instance as a const
++ inline const boost::asio::ip::icmp::endpoint& getASIOEndpoint() const {
++ return (asio_endpoint_);
++ }
++
++ /// @brief Fetches the underlying ASIO endpoint implementation
++ ///
++ /// This is not part of the exposed IOEndpoint API but allows
++ /// direct access to the ASIO implementation of the endpoint
++ ///
++ /// @return the wrapped ASIO endpoint instance as a non-const
++ inline boost::asio::ip::icmp::endpoint& getASIOEndpoint() {
++ return (asio_endpoint_);
++ }
++
++private:
++ /// @brief Pointer to the ASIO endpoint placeholder.
++ boost::asio::ip::icmp::endpoint* asio_endpoint_placeholder_;
++
++ /// @brief Reference to the underlying ASIO endpoint instance.
++ boost::asio::ip::icmp::endpoint& asio_endpoint_;
++};
++
++} // namespace ping_check
++} // namespace isc
++#endif // ICMP_ENDPOINT_H
+diff --git a/src/hooks/dhcp/ping_check/icmp_msg.cc b/src/hooks/dhcp/ping_check/icmp_msg.cc
+new file mode 100644
+index 0000000000..3d236820da
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/icmp_msg.cc
+@@ -0,0 +1,112 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++#include <icmp_msg.h>
++#include <util/io.h>
++#include <exceptions/exceptions.h>
++
++#include <netinet/ip_icmp.h>
++#include <iostream>
++
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::util;
++
++namespace isc {
++namespace ping_check {
++
++ICMPMsg::ICMPMsg()
++ : source_(IOAddress::IPV4_ZERO_ADDRESS()),
++ destination_(IOAddress::IPV4_ZERO_ADDRESS()),
++ msg_type_(0), code_(0), check_sum_(0), id_(0), sequence_(0),
++ payload_(0) {
++}
++
++ICMPMsgPtr
++ICMPMsg::unpack(const uint8_t* wire_data, size_t length) {
++ ICMPMsgPtr msg(new ICMPMsg());
++ if (length < sizeof(struct ip)) {
++ isc_throw(BadValue,
++ "ICMPMsg::unpack - truncated ip header, length: "
++ << length);
++ }
++
++ // Find the IP header length...
++ struct ip* ip_header = (struct ip*)(wire_data);
++ auto hlen = (ip_header->ip_hl << 2);
++
++ // Make sure we received enough data.
++ if (length < (hlen + sizeof(struct icmp))) {
++ isc_throw(BadValue, "ICMPMsg::truncated packet? length: "
++ << length << ", hlen: " << hlen);
++ }
++
++ // Grab the source and destination addresses.
++ msg->setSource(IOAddress(ntohl(ip_header->ip_src.s_addr)));
++ msg->setDestination(IOAddress(ntohl(ip_header->ip_dst.s_addr)));
++
++ // Get the message type.
++ struct icmp* reply = (struct icmp*)(wire_data + hlen);
++ msg->setType(reply->icmp_type);
++ msg->setCode(reply->icmp_code);
++
++ msg->setChecksum(ntohs(reply->icmp_cksum));
++ msg->setId(ntohs(reply->icmp_hun.ih_idseq.icd_id));
++ msg->setSequence(ntohs(reply->icmp_hun.ih_idseq.icd_seq));
++
++ auto payload_len = length - hlen - ICMP_HEADER_SIZE;
++ msg->setPayload((const uint8_t*)(&reply->icmp_dun), payload_len);
++
++ return (msg);
++}
++
++ICMPPtr
++ICMPMsg::pack() const {
++ ICMPPtr outbound(new struct icmp());
++ memset(outbound.get(), 0x00, sizeof(struct icmp));
++ outbound->icmp_type = msg_type_;
++ outbound->icmp_id = htons(id_);
++ outbound->icmp_seq = htons(sequence_);
++ /// @todo copy in payload - not needed for ECHO REQUEST
++ outbound->icmp_cksum = htons(~calcChecksum((const uint8_t*)(outbound.get()), sizeof(struct icmp)));
++ return (outbound);
++}
++
++void
++ICMPMsg::setPayload(const uint8_t* data, size_t length) {
++ payload_.insert(payload_.end(), data, data + length);
++}
++
++uint32_t
++ICMPMsg::calcChecksum(const uint8_t* buf, size_t length) {
++ uint32_t sum = 0;
++
++ /* Checksum all the pairs of bytes first... */
++ size_t i;
++ for (i = 0; i < (length & ~1U); i += 2) {
++ sum += static_cast<uint32_t>(readUint16(buf + i, sizeof(uint16_t)));
++ /* Add carry. */
++ if (sum > 0xFFFF) {
++ sum -= 0xFFFF;
++ }
++ }
++
++ /* If there's a single byte left over, checksum it, too. Network
++ byte order is big-endian, so the remaining byte is the high byte. */
++ if (i < length) {
++ sum += buf[i] << 8;
++ /* Add carry. */
++ if (sum > 0xFFFF) {
++ sum -= 0xFFFF;
++ }
++ }
++
++ return (sum);
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/icmp_msg.h b/src/hooks/dhcp/ping_check/icmp_msg.h
+new file mode 100644
+index 0000000000..ace322d1ca
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/icmp_msg.h
+@@ -0,0 +1,223 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef ICMP_MSG_H
++#define ICMP_MSG_H
++
++#include <asiolink/io_address.h>
++
++#include <arpa/inet.h>
++#include <netinet/in.h>
++#include <netinet/ip.h>
++#include <unistd.h>
++#include <netinet/ip_icmp.h>
++#include <boost/shared_ptr.hpp>
++
++namespace isc {
++namespace ping_check {
++
++// Forward class definition.
++class ICMPMsg;
++
++/// @brief Shared pointer type for ICMPMsg.
++typedef boost::shared_ptr<ICMPMsg> ICMPMsgPtr;
++
++/// @brief Shared pointer type for struct icmp.
++typedef boost::shared_ptr<struct icmp> ICMPPtr;
++
++/// @brief Embodies an ICMP message
++///
++/// Provides functions for marshalling of ICMP protocol
++/// messages to and from wire form
++class ICMPMsg {
++public:
++ /// @brief ICMP message types. We only define the ones
++ /// we care about.
++ enum ICMPMsgType {
++ ECHO_REPLY = 0,
++ TARGET_UNREACHABLE = 3,
++ ECHO_REQUEST = 8
++ };
++
++ /// @brief Size in octets of ICMP message header.
++ /// 1 (msg type) + 1 (code) + 2 (checksum) + 4 (either unused
++ /// or used differently basing on the ICMP type and code e.g
++ /// Identifier and Sequence Number for Echo or Echo Reply Message)
++ constexpr static size_t ICMP_HEADER_SIZE = 8;
++
++ /// @brief Constructor.
++ ICMPMsg();
++
++ /// @brief Destructor.
++ virtual ~ICMPMsg() = default;
++
++ /// @brief Unpacks an ICMP message from the given wire_data
++ ///
++ /// The wire data is expected to include the IP header followed
++ /// by an ICMP message.
++ ///
++ /// @param wire_data raw data received from the socket
++ /// @param length number of bytes in the wire_data contents
++ ///
++ /// @return Pointer to the newly constructed message
++ /// @throw BadValue if the wire data is invalid
++ static ICMPMsgPtr unpack(const uint8_t* wire_data, size_t length);
++
++ /// @brief Packs the message into an ICMP structure.
++ ///
++ /// @return Pointer to the newly constructed ICMP structure.
++ ICMPPtr pack() const;
++
++ /// @brief Fetches the ICMP message type (e.g. ECHO_REQUEST, ECHO_REPLY)
++ ///
++ /// @return message type as a uint8_t
++ uint8_t getType() const {
++ return (msg_type_);
++ }
++
++ /// @brief Sets the ICMP message type
++ ///
++ /// @param msg_type new value for the message type
++ void setType(uint8_t msg_type) {
++ msg_type_ = msg_type;
++ }
++
++ /// @brief Fetches the ICMP message code
++ ///
++ /// @return uint8_t containing the message code
++ uint8_t getCode() const {
++ return (code_);
++ }
++
++ /// @brief Sets the ICMP code
++ ///
++ /// @param code new value for the message type
++ void setCode(uint8_t code) {
++ code_ = code;
++ }
++
++ /// @brief Fetches the checksum
++ ///
++ /// @return uint16_t containing the message checksum
++ uint16_t getChecksum() const {
++ return (check_sum_);
++ }
++
++ /// @brief Sets the check sum
++ ///
++ /// @param check_sum new value for the check sum
++ void setChecksum(uint16_t check_sum) {
++ check_sum_ = check_sum;
++ }
++
++ /// @brief Fetches the message id
++ ///
++ /// @return uint16_t containing the id
++ uint16_t getId() const {
++ return (id_);
++ }
++
++ /// @brief Sets the message id
++ ///
++ /// @param id new value for the message id
++ void setId(const uint16_t id) {
++ id_ = id;
++ }
++
++ /// @brief Fetches the message sequence number
++ ///
++ /// @return uint16_t containing the sequence number
++ uint16_t getSequence() const {
++ return (sequence_);
++ }
++
++ /// @brief Sets the message sequence number
++ ///
++ /// @param sequence new value for the message sequence number
++ void setSequence(uint16_t sequence) {
++ sequence_ = sequence;
++ }
++
++ /// @brief Fetches the source IP address
++ ///
++ /// @return IOAddress containing the IP address of the message source
++ const isc::asiolink::IOAddress& getSource() const {
++ return (source_);
++ }
++
++ /// @brief Sets the source IP address
++ ///
++ /// @param source new value for the source IP address
++ void setSource(const isc::asiolink::IOAddress& source) {
++ source_ = source;
++ }
++
++ /// @brief Fetches the destination IP address
++ ///
++ /// @return IOAddress containing the IP address of the message destination
++ const isc::asiolink::IOAddress& getDestination() const {
++ return (destination_);
++ }
++
++ /// @brief Sets the destination IP address
++ ///
++ /// @param destination new value for the destination IP address
++ void setDestination(const isc::asiolink::IOAddress& destination) {
++ destination_ = destination;
++ }
++
++ /// @brief Fetches the message payload
++ ///
++ /// @return vector containing the message payload
++ const std::vector<uint8_t>& getPayload() const {
++ return (payload_);
++ }
++
++ /// @brief Sets the message payload to the given data
++ ///
++ /// @param data pointer to data buffer from which to copy
++ /// @param length number of bytes in data buffer
++ void setPayload(const uint8_t* data, size_t length);
++
++ /// @brief Calculates the checksum of the given data buffer
++ ///
++ /// @param data pointer to data buffer from which to copy
++ /// @param length number of bytes in data buffer
++ ///
++ /// @return uint32_t containing the calculated checksum
++ static uint32_t calcChecksum(const uint8_t* data, size_t length);
++
++private:
++ /// @brief IP address from which the message origin
++ isc::asiolink::IOAddress source_;
++
++ /// @brief IP address of the message destination
++ isc::asiolink::IOAddress destination_;
++
++ /// @brief ICMP message type
++ uint8_t msg_type_;
++
++ /// @brief ICMP message code
++ uint8_t code_;
++
++ /// @brief Checksum of the message
++ uint16_t check_sum_;
++
++ /// @brief Message ID
++ uint16_t id_;
++
++ /// @brief Message sequence number
++ uint16_t sequence_;
++
++ // data beyond the ICMP header
++ std::vector<uint8_t> payload_;
++};
++
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/icmp_socket.h b/src/hooks/dhcp/ping_check/icmp_socket.h
+new file mode 100644
+index 0000000000..091057d749
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/icmp_socket.h
+@@ -0,0 +1,359 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef ICMP_SOCKET_H
++#define ICMP_SOCKET_H 1
++
++#include <netinet/in.h>
++#include <sys/socket.h>
++#include <unistd.h>
++
++#include <cstddef>
++
++#include <asiolink/io_asio_socket.h>
++#include <asiolink/io_service.h>
++#include <icmp_endpoint.h>
++
++#include <exceptions/isc_assert.h>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief The @c ICMPSocket class is a concrete derived class of @c IOAsioSocket
++/// that represents a ICMP socket.
++///
++/// @param C Callback type
++template <typename C>
++class ICMPSocket : public asiolink::IOAsioSocket<C> {
++private:
++ /// @brief Class is non-copyable
++ explicit ICMPSocket(const ICMPSocket&);
++ ICMPSocket& operator=(const ICMPSocket&);
++
++public:
++ enum {
++ MIN_SIZE = 4096 // Minimum send and receive size
++ };
++
++ /// @brief Constructor from an ASIO ICMP socket.
++ ///
++ /// @param socket The ASIO representation of the ICMP socket. It is assumed
++ /// that the caller will open and close the socket, so these
++ /// operations are a no-op for that socket.
++ explicit ICMPSocket(boost::asio::ip::icmp::socket& socket);
++
++ /// @brief Constructor
++ ///
++ /// Used when the ICMPSocket is being asked to manage its own internal
++ /// socket. In this case, the open() and close() methods are used.
++ ///
++ /// @param service I/O Service object used to manage the socket.
++ explicit ICMPSocket(const asiolink::IOServicePtr& service);
++
++ /// @brief Destructor
++ virtual ~ICMPSocket();
++
++ /// @brief Return file descriptor of underlying socket
++ ///
++ /// @return socket's native file descriptor as an int.
++ virtual int getNative() const {
++#if BOOST_VERSION < 106600
++ return (socket_.native());
++#else
++ return (socket_.native_handle());
++#endif
++ }
++
++ /// @brief Return protocol of socket
++ ///
++ /// @return Always IPPROTO_ICMP.
++ virtual int getProtocol() const {
++ return (IPPROTO_ICMP);
++ }
++
++ /// @brief Is "open()" synchronous?
++ ///
++ /// Indicates that the opening of a ICMP socket is synchronous.
++ /// @return Always true.
++ virtual bool isOpenSynchronous() const {
++ return true;
++ }
++
++ /// @brief Indicates if the socket is currently open.
++ ///
++ /// @return true if socket is open.
++ virtual bool isOpen() const {
++ return isopen_;
++ }
++
++ /// @brief Open Socket
++ ///
++ /// Opens the ICMP socket. This is a synchronous operation.
++ ///
++ /// @param endpoint Endpoint to which the socket will send data. This is
++ /// used to determine the address family that should be used for the
++ /// underlying socket.
++ /// @param callback Unused as the operation is synchronous.
++ virtual void open(const asiolink::IOEndpoint* endpoint, C& callback);
++
++ /// @brief Send Asynchronously
++ ///
++ /// Calls the underlying socket's async_send_to() method to send a packet of
++ /// data asynchronously to the remote endpoint. The callback will be called
++ /// on completion.
++ ///
++ /// @param data Data to send
++ /// @param length Length of data to send
++ /// @param endpoint Target of the send
++ /// @param callback Callback object.
++ virtual void asyncSend(const void* data, size_t length,
++ const asiolink::IOEndpoint* endpoint, C& callback);
++
++ /// @brief Receive Asynchronously
++ ///
++ /// Calls the underlying socket's async_receive_from() method to read a
++ /// packet of data from a remote endpoint. Arrival of the data is signalled
++ /// via a call to the callback function.
++ ///
++ /// @param data Buffer to receive incoming message
++ /// @param length Length of the data buffer
++ /// @param offset Offset into buffer where data is to be put
++ /// @param endpoint Source of the communication
++ /// @param callback Callback object
++ virtual void asyncReceive(void* data, size_t length, size_t offset,
++ asiolink::IOEndpoint* endpoint, C& callback);
++
++ /// @brief Process received data
++ ///
++ /// See the description of IOAsioSocket::receiveComplete for a complete
++ /// description of this method.
++ ///
++ /// @param staging Pointer to the start of the staging buffer.
++ /// @param length Amount of data in the staging buffer.
++ /// @param cumulative Amount of data received before the staging buffer is
++ /// processed.
++ /// @param offset Unused.
++ /// @param expected unused.
++ /// @param outbuff Output buffer. Data in the staging buffer is be copied
++ /// to this output buffer in the call.
++ ///
++ /// @return Always true
++ virtual bool processReceivedData(const void* staging, size_t length,
++ size_t& cumulative, size_t& offset,
++ size_t& expected,
++ isc::util::OutputBufferPtr& outbuff);
++
++ /// @brief Cancel I/O On Socket
++ virtual void cancel();
++
++ /// @brief Close socket
++ virtual void close();
++
++ /// @brief Calculates the checksum for the given buffer of data.
++ ///
++ /// @param buf pointer to the data buffer.
++ /// @param buf_size number of bytes in the data buffer.
++ ///
++ /// @return calculated checksum of the data as a uint16_t.
++ static uint16_t calcChecksum(const uint8_t* buf, const uint32_t buf_size);
++
++private:
++ /// @brief The IO service used to handle events.
++ isc::asiolink::IOServicePtr io_service_;
++
++ // Two variables to hold the socket - a socket and a pointer to it. This
++ // handles the case where a socket is passed to the ICMPSocket on
++ // construction, or where it is asked to manage its own socket.
++
++ /// Pointer to own socket
++ std::unique_ptr<boost::asio::ip::icmp::socket> socket_ptr_;
++
++ // Socket
++ boost::asio::ip::icmp::socket& socket_;
++
++ // True when socket is open
++ bool isopen_;
++};
++
++// Constructor - caller manages socket
++
++template <typename C>
++ICMPSocket<C>::ICMPSocket(boost::asio::ip::icmp::socket& socket) :
++ socket_ptr_(), socket_(socket), isopen_(true) {
++}
++
++// Constructor - create socket on the fly
++
++template <typename C>
++ICMPSocket<C>::ICMPSocket(const asiolink::IOServicePtr& io_service) :
++ io_service_(io_service),
++ socket_ptr_(new boost::asio::ip::icmp::socket(io_service_->getInternalIOService())),
++ socket_(*socket_ptr_), isopen_(false) {
++}
++
++// Destructor.
++
++template <typename C>
++ICMPSocket<C>::~ICMPSocket() {
++}
++
++// Open the socket.
++
++template <typename C> void
++ICMPSocket<C>::open(const asiolink::IOEndpoint* endpoint, C&) {
++
++ // Ignore opens on already-open socket. (Don't throw a failure because
++ // of uncertainties as to what precedes when using asynchronous I/O.)
++ // It also allows us a treat a passed-in socket in exactly the same way as
++ // a self-managed socket (in that we can call the open() and close() methods
++ // of this class).
++ if (!isopen_) {
++ if (endpoint->getFamily() == AF_INET) {
++ socket_.open(boost::asio::ip::icmp::v4());
++ } else {
++ socket_.open(boost::asio::ip::icmp::v6());
++ }
++ isopen_ = true;
++
++ // Ensure it can send and receive at least 4K buffers.
++ boost::asio::ip::icmp::socket::send_buffer_size snd_size;
++ socket_.get_option(snd_size);
++ if (snd_size.value() < MIN_SIZE) {
++ snd_size = MIN_SIZE;
++ socket_.set_option(snd_size);
++ }
++
++ boost::asio::ip::icmp::socket::receive_buffer_size rcv_size;
++ socket_.get_option(rcv_size);
++ if (rcv_size.value() < MIN_SIZE) {
++ rcv_size = MIN_SIZE;
++ socket_.set_option(rcv_size);
++ }
++
++ boost::asio::socket_base::do_not_route option(true);
++ socket_.set_option(option);
++ }
++}
++
++// Send a message. Should never do this if the socket is not open, so throw
++// an exception if this is the case.
++
++template <typename C> void
++ICMPSocket<C>::asyncSend(const void* data, size_t length,
++ const asiolink::IOEndpoint* endpoint, C& callback) {
++ if (isopen_) {
++
++ // Upconvert to a ICMPEndpoint. We need to do this because although
++ // IOEndpoint is the base class of ICMPEndpoint and TCPEndpoint, it
++ // does not contain a method for getting at the underlying endpoint
++ // type - that is in the derived class and the two classes differ on
++ // return type.
++ isc_throw_assert(endpoint->getProtocol() == IPPROTO_ICMP);
++ const ICMPEndpoint* udp_endpoint =
++ static_cast<const ICMPEndpoint*>(endpoint);
++
++ // ... and send the message.
++ socket_.async_send_to(boost::asio::buffer(data, length),
++ udp_endpoint->getASIOEndpoint(), callback);
++ } else {
++ isc_throw(asiolink::SocketNotOpen,
++ "attempt to send on a ICMP socket that is not open");
++ }
++}
++
++// Receive a message. Should never do this if the socket is not open, so throw
++// an exception if this is the case.
++
++template <typename C> void
++ICMPSocket<C>::asyncReceive(void* data, size_t length, size_t offset,
++ asiolink::IOEndpoint* endpoint, C& callback) {
++ if (isopen_) {
++
++ // Upconvert the endpoint again.
++ isc_throw_assert(endpoint->getProtocol() == IPPROTO_ICMP);
++ ICMPEndpoint* udp_endpoint = static_cast<ICMPEndpoint*>(endpoint);
++
++ // Ensure we can write into the buffer
++ if (offset >= length) {
++ isc_throw(asiolink::BufferOverflow, "attempt to read into area beyond end of "
++ "ICMP receive buffer");
++ }
++ void* buffer_start = static_cast<void*>(static_cast<uint8_t*>(data) + offset);
++
++ // Issue the read
++ socket_.async_receive_from(boost::asio::buffer(buffer_start, length - offset),
++ udp_endpoint->getASIOEndpoint(), callback);
++ } else {
++ isc_throw(asiolink::SocketNotOpen,
++ "attempt to receive from a ICMP socket that is not open");
++ }
++}
++
++// Receive complete. Just copy the data across to the output buffer and
++// update arguments as appropriate.
++
++template <typename C> bool
++ICMPSocket<C>::processReceivedData(const void* staging, size_t length,
++ size_t& cumulative, size_t& offset,
++ size_t& expected,
++ isc::util::OutputBufferPtr& outbuff) {
++ // Set return values to what we should expect.
++ cumulative = length;
++ expected = length;
++ offset = 0;
++
++ // Copy data across
++ outbuff->writeData(staging, length);
++
++ // ... and mark that we have everything.
++ return (true);
++}
++
++// Cancel I/O on the socket. No-op if the socket is not open.
++
++template <typename C> void
++ICMPSocket<C>::cancel() {
++ if (isopen_) {
++ socket_.cancel();
++ }
++}
++
++// Close the socket down. Can only do this if the socket is open and we are
++// managing it ourself.
++
++template <typename C> void
++ICMPSocket<C>::close() {
++ if (isopen_ && socket_ptr_) {
++ socket_.close();
++ isopen_ = false;
++ }
++}
++
++template <typename C> uint16_t
++ICMPSocket<C>::calcChecksum(const uint8_t* buf, const uint32_t buf_size) {
++ uint32_t sum = 0;
++ uint32_t i;
++ for (i = 0; i < (buf_size & ~1U); i += 2) {
++ uint16_t chunk = buf[i] << 8 | buf[i + 1];
++ sum += chunk;
++ if (sum > 0xFFFF) {
++ sum -= 0xFFFF;
++ }
++ }
++ // If one byte has left, we also need to add it to the checksum.
++ if (i < buf_size) {
++ sum += buf[i] << 8;
++ if (sum > 0xFFFF) {
++ sum -= 0xFFFF;
++ }
++ }
++
++ return (sum);
++}
++
++} // namespace ping_check
++} // namespace isc
++#endif // ICMP_SOCKET_H
+diff --git a/src/hooks/dhcp/ping_check/libloadtests/.gitignore b/src/hooks/dhcp/ping_check/libloadtests/.gitignore
+new file mode 100644
+index 0000000000..ada6ed5036
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/libloadtests/.gitignore
+@@ -0,0 +1 @@
++hook_load_unittests
+diff --git a/src/hooks/dhcp/ping_check/libloadtests/Makefile.am b/src/hooks/dhcp/ping_check/libloadtests/Makefile.am
+new file mode 100644
+index 0000000000..139a068b3c
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/libloadtests/Makefile.am
+@@ -0,0 +1,60 @@
++SUBDIRS = .
++
++AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
++AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/ping_check -I$(top_srcdir)/src/hooks/dhcp/ping_check
++AM_CPPFLAGS += $(BOOST_INCLUDES) $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
++AM_CPPFLAGS += -DPING_CHECK_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/ping_check/.libs/libdhcp_ping_check.so\"
++AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
++
++AM_CXXFLAGS = $(KEA_CXXFLAGS)
++
++if USE_STATIC_LINK
++AM_LDFLAGS = -static
++endif
++
++# Unit test data files need to get installed.
++EXTRA_DIST =
++
++CLEANFILES = *.gcno *.gcda
++
++TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
++
++LOG_COMPILER = $(LIBTOOL)
++AM_LOG_FLAGS = --mode=execute
++
++TESTS =
++if HAVE_GTEST
++TESTS += hook_load_unittests
++
++hook_load_unittests_SOURCES = run_unittests.cc
++hook_load_unittests_SOURCES += load_unload_unittests.cc
++
++hook_load_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
++
++hook_load_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
++
++hook_load_unittests_CXXFLAGS = $(AM_CXXFLAGS)
++
++hook_load_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
++hook_load_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
++hook_load_unittests_LDADD += $(LOG4CPLUS_LIBS)
++hook_load_unittests_LDADD += $(CRYPTO_LIBS)
++hook_load_unittests_LDADD += $(BOOST_LIBS)
++hook_load_unittests_LDADD += $(GTEST_LDADD)
++endif
++noinst_PROGRAMS = $(TESTS)
+diff --git a/src/hooks/dhcp/ping_check/libloadtests/load_unload_unittests.cc b/src/hooks/dhcp/ping_check/libloadtests/load_unload_unittests.cc
+new file mode 100644
+index 0000000000..67275db617
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/libloadtests/load_unload_unittests.cc
+@@ -0,0 +1,107 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the load and unload
++/// functions in the ddns tuning hook library. In order to test the load
++/// function, one must be able to pass it hook library parameters. The
++/// the only way to populate these parameters is by actually loading the
++/// library via HooksManager::loadLibraries().
++
++#include <config.h>
++
++#include <dhcpsrv/testutils/lib_load_test_fixture.h>
++#include <testutils/gtest_utils.h>
++
++#include <gtest/gtest.h>
++#include <errno.h>
++
++using namespace std;
++using namespace isc;
++using namespace isc::hooks;
++using namespace isc::data;
++using namespace isc::dhcp;
++using namespace isc::process;
++
++namespace {
++
++/// @brief Test fixture for testing loading and unloading the ddns tuning library
++class PingCheckLibLoadTest : public isc::test::LibLoadTest {
++public:
++ /// @brief Constructor
++ PingCheckLibLoadTest() : LibLoadTest(PING_CHECK_LIB_SO) {
++ }
++
++ /// @brief Destructor
++ virtual ~PingCheckLibLoadTest() {
++ }
++
++ /// @brief Registers hooks in the hook manager.
++ /// Normally this is done by the server core code (@c Dhcpv4Srv).
++ void registerHooks() {
++ hook_index_dhcp4_srv_configured_ = HooksManager::registerHook("dhcp4_srv_configured");
++ hook_index_lease4_offer_ = HooksManager::registerHook("lease4_offer");
++ }
++
++ /// @brief Checks that expected callouts are present.
++ void calloutsPresent() {
++ bool result;
++ ASSERT_NO_THROW_LOG(result = HooksManager::calloutsPresent(hook_index_dhcp4_srv_configured_));
++ EXPECT_TRUE(result);
++ ASSERT_NO_THROW_LOG(result = HooksManager::calloutsPresent(hook_index_lease4_offer_));
++ EXPECT_TRUE(result);
++ }
++
++ /// @brief Creates a valid set of ping-check hook parameters.
++ virtual ElementPtr validConfigParams() {
++ ElementPtr params = Element::createMap();
++ params->set("min-ping-requests", Element::create(3));
++ params->set("reply-timeout", Element::create(100));
++ params->set("enable-ping-check", Element::create(true));
++ params->set("ping-cltt-secs", Element::create(60));
++ params->set("ping-channel-threads", Element::create(1));
++ return (params);
++ }
++
++ /// @brief Hook index values.
++ int hook_index_dhcp4_srv_configured_;
++ int hook_index_lease4_offer_;
++};
++
++// Simple V4 test that checks the library can be loaded and unloaded several times.
++TEST_F(PingCheckLibLoadTest, validLoad4) {
++ validDaemonTest("kea-dhcp4", AF_INET, valid_params_);
++}
++
++// Simple test that checks the library cannot be loaded by invalid daemons.
++TEST_F(PingCheckLibLoadTest, invalidDaemonLoad) {
++ // V6 is invalid regardless of family.
++ invalidDaemonTest("kea-dhcp6", AF_INET, valid_params_);
++ invalidDaemonTest("kea-dhcp6", AF_INET6, valid_params_);
++
++ invalidDaemonTest("kea-ctrl-agent", AF_INET, valid_params_);
++ invalidDaemonTest("kea-dhcp-ddns", AF_INET, valid_params_);
++ invalidDaemonTest("bogus", AF_INET, valid_params_);
++}
++
++// Verifies that callout functions exist after loading the library.
++TEST_F(PingCheckLibLoadTest, verifyCallouts) {
++ // Set family and daemon's proc name and register hook points.
++ isc::dhcp::CfgMgr::instance().setFamily(AF_INET);
++ isc::process::Daemon::setProcName("kea-dhcp4");
++ registerHooks();
++
++ // Add library to config and load it.
++ ASSERT_NO_THROW_LOG(addLibrary(lib_so_name_, valid_params_));
++ ASSERT_NO_THROW_LOG(loadLibraries());
++
++ // Verify that expected callouts are present.
++ calloutsPresent();
++
++ // Unload the library.
++ ASSERT_NO_THROW_LOG(unloadLibraries());
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/libloadtests/meson.build b/src/hooks/dhcp/ping_check/libloadtests/meson.build
+new file mode 100644
+index 0000000000..da8bf439c0
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/libloadtests/meson.build
+@@ -0,0 +1,21 @@
++if not TESTS_OPT.enabled()
++ subdir_done()
++endif
++
++dhcp_ping_check_libloadtests = executable(
++ 'dhcp-ping-check-libload-tests',
++ 'load_unload_unittests.cc',
++ 'run_unittests.cc',
++ cpp_args: [
++ f'-DPING_CHECK_LIB_SO="@TOP_BUILD_DIR@/src/hooks/dhcp/ping_check/libdhcp_ping_check.so"',
++ ],
++ dependencies: [GTEST_DEP, CRYPTO_DEP],
++ include_directories: [include_directories('.')] + INCLUDES,
++ link_with: LIBS_BUILT_SO_FAR,
++)
++test(
++ 'dhcp-ping-check-libloadtests',
++ dhcp_ping_check_libloadtests,
++ depends: [dhcp_ping_check_lib],
++ protocol: 'gtest',
++)
+diff --git a/src/hooks/dhcp/ping_check/libloadtests/run_unittests.cc b/src/hooks/dhcp/ping_check/libloadtests/run_unittests.cc
+new file mode 100644
+index 0000000000..d249e2362e
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/libloadtests/run_unittests.cc
+@@ -0,0 +1,19 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <log/logger_support.h>
++#include <gtest/gtest.h>
++
++int
++main(int argc, char* argv[]) {
++ ::testing::InitGoogleTest(&argc, argv);
++ isc::log::initLogger();
++ int result = RUN_ALL_TESTS();
++
++ return (result);
++}
+diff --git a/src/hooks/dhcp/ping_check/meson.build b/src/hooks/dhcp/ping_check/meson.build
+new file mode 100644
+index 0000000000..d3a1e70b49
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/meson.build
+@@ -0,0 +1,41 @@
++dhcp_ping_check_lib = shared_library(
++ 'dhcp_ping_check',
++ 'config_cache.cc',
++ 'icmp_msg.cc',
++ 'ping_channel.cc',
++ 'ping_check_callouts.cc',
++ 'ping_check_config.cc',
++ 'ping_check_log.cc',
++ 'ping_check_messages.cc',
++ 'ping_check_mgr.cc',
++ 'ping_context.cc',
++ 'ping_context_store.cc',
++ 'version.cc',
++ dependencies: [CRYPTO_DEP],
++ include_directories: [include_directories('.')] + INCLUDES,
++ install: true,
++ install_dir: HOOKS_PATH,
++ install_rpath: INSTALL_RPATH,
++ build_rpath: BUILD_RPATH,
++ link_with: LIBS_BUILT_SO_FAR,
++ name_suffix: 'so',
++)
++dhcp_ping_check_archive = static_library(
++ 'dhcp_ping_check',
++ objects: dhcp_ping_check_lib.extract_all_objects(recursive: false),
++)
++subdir('libloadtests')
++subdir('tests')
++
++if KEA_MSG_COMPILER.found()
++ target_gen_messages = run_target(
++ 'src-hooks-dhcp-ping_check-ping_check_messages',
++ command: [
++ CD_AND_RUN,
++ TOP_SOURCE_DIR,
++ KEA_MSG_COMPILER,
++ 'src/hooks/dhcp/ping_check/ping_check_messages.mes',
++ ],
++ )
++ TARGETS_GEN_MESSAGES += [target_gen_messages]
++endif
+diff --git a/src/hooks/dhcp/ping_check/ping_channel.cc b/src/hooks/dhcp/ping_check/ping_channel.cc
+new file mode 100644
+index 0000000000..6a6a88c038
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_channel.cc
+@@ -0,0 +1,466 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++#include <ping_channel.h>
++#include <ping_check_log.h>
++#include <dhcp/iface_mgr.h>
++#include <exceptions/exceptions.h>
++#include <util/multi_threading_mgr.h>
++#include <iostream>
++
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::util;
++
++namespace ph = std::placeholders;
++
++namespace isc {
++namespace ping_check {
++
++uint32_t
++PingChannel::nextEchoInstanceNum() {
++ static uint32_t echo_instance_num = 0x00010000;
++ if (echo_instance_num == UINT32_MAX) {
++ echo_instance_num = 0x00010001;
++ } else {
++ ++echo_instance_num;
++ }
++
++ return (echo_instance_num);
++}
++
++PingChannel::PingChannel(IOServicePtr& io_service,
++ NextToSendCallback next_to_send_cb,
++ EchoSentCallback echo_sent_cb,
++ ReplyReceivedCallback reply_received_cb,
++ ShutdownCallback shutdown_cb)
++ : io_service_(io_service),
++ next_to_send_cb_(next_to_send_cb),
++ echo_sent_cb_(echo_sent_cb),
++ reply_received_cb_(reply_received_cb),
++ shutdown_cb_(shutdown_cb),
++ socket_(0), input_buf_(256),
++ reading_(false), sending_(false), stopping_(false), mutex_(new std::mutex),
++ single_threaded_(!MultiThreadingMgr::instance().getMode()),
++ watch_socket_(0), registered_write_fd_(-1), registered_read_fd_(-1) {
++ if (!io_service_) {
++ isc_throw(BadValue,
++ "PingChannel ctor - io_service cannot be empty");
++ }
++}
++
++PingChannel::~PingChannel() {
++ close();
++}
++
++void
++PingChannel::open() {
++ try {
++ MultiThreadingLock lock(*mutex_);
++ if (socket_ && socket_->isOpen()) {
++ return;
++ }
++
++ // For open(), the endpoint is only used to determine protocol,
++ // the address is irrelevant.
++ ICMPEndpoint ping_to_endpoint(IOAddress::IPV4_ZERO_ADDRESS());
++ SocketCallback socket_cb(
++ [](boost::system::error_code ec, size_t /*length */) {
++ isc_throw(Unexpected, "ICMPSocket open is synchronous, should not invoke cb: "
++ << ec.message());
++ }
++ );
++
++ socket_.reset(new PingSocket(io_service_));
++ socket_->open(&ping_to_endpoint, socket_cb);
++ reading_ = false;
++ sending_ = false;
++ stopping_ = false;
++
++ if (single_threaded_) {
++ // Open new watch socket.
++ watch_socket_.reset(new util::WatchSocket());
++
++ // Register the WatchSocket with IfaceMgr to signal data ready to write.
++ registered_write_fd_ = watch_socket_->getSelectFd();
++ IfaceMgr::instance().addExternalSocket(registered_write_fd_, IfaceMgr::SocketCallback());
++
++ // Register ICMPSocket with IfaceMgr to signal data ready to read.
++ registered_read_fd_ = socket_->getNative();
++ IfaceMgr::instance().addExternalSocket(registered_read_fd_, IfaceMgr::SocketCallback());
++ }
++
++ } catch (const std::exception& ex) {
++ isc_throw(Unexpected, "PingChannel::open failed:" << ex.what());
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC, PING_CHECK_CHANNEL_SOCKET_OPENED);
++}
++
++bool
++PingChannel::isOpen() const {
++ MultiThreadingLock lock(*mutex_);
++ return (socket_ && socket_->isOpen());
++}
++
++void
++PingChannel::close() {
++ try {
++ MultiThreadingLock lock(*mutex_);
++
++ if (single_threaded_) {
++ // Unregister from IfaceMgr.
++ if (registered_write_fd_ != -1) {
++ IfaceMgr::instance().deleteExternalSocket(registered_write_fd_);
++ registered_write_fd_ = -1;
++ }
++
++ if (registered_read_fd_ != -1) {
++ IfaceMgr::instance().deleteExternalSocket(registered_read_fd_);
++ registered_read_fd_ = -1;
++ }
++
++ // Close watch socket.
++ if (watch_socket_) {
++ std::string error_string;
++ watch_socket_->closeSocket(error_string);
++ if (!error_string.empty()) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR)
++ .arg(error_string);
++ }
++
++ watch_socket_.reset();
++ }
++ }
++
++ if (!socket_ || !socket_->isOpen()) {
++ return;
++ }
++
++ socket_->close();
++ } catch (const std::exception& ex) {
++ // On close error, log but do not throw.
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR)
++ .arg(ex.what());
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC, PING_CHECK_CHANNEL_SOCKET_CLOSED);
++}
++
++void
++PingChannel::stopChannel() {
++ {
++ MultiThreadingLock lock(*mutex_);
++ if (stopping_) {
++ return;
++ }
++
++ stopping_ = true;
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC, PING_CHECK_CHANNEL_STOP);
++ close();
++
++ if (shutdown_cb_) {
++ (shutdown_cb_)();
++ }
++}
++
++void
++PingChannel::asyncReceive(void* data, size_t length, size_t offset,
++ asiolink::IOEndpoint* endpoint, SocketCallback& callback) {
++ socket_->asyncReceive(data, length, offset, endpoint, callback);
++}
++
++void
++PingChannel::asyncSend(void* data, size_t length, asiolink::IOEndpoint* endpoint,
++ SocketCallback& callback) {
++ socket_->asyncSend(data, length, endpoint, callback);
++
++ if (single_threaded_) {
++ // Set IO ready marker so sender activity is visible to select() or poll().
++ watch_socket_->markReady();
++ }
++}
++
++void
++PingChannel::doRead() {
++ try {
++ MultiThreadingLock lock(*mutex_);
++ if (!canRead()) {
++ return;
++ }
++
++ reading_ = true;
++
++ // Create instance of the callback. It is safe to pass the
++ // local instance of the callback, because the underlying
++ // std functions make copies as needed.
++ SocketCallback cb(std::bind(&PingChannel::socketReadCallback,
++ shared_from_this(),
++ ph::_1, // error
++ ph::_2)); // bytes_transferred
++ asyncReceive(static_cast<void*>(getInputBufData()), getInputBufSize(),
++ 0, &reply_endpoint_, cb);
++ } catch (const std::exception& ex) {
++ // Normal IO failures should be passed to the callback. A failure here
++ // indicates the call to asyncReceive() itself failed.
++ LOG_ERROR(ping_check_logger, PING_CHECK_UNEXPECTED_READ_ERROR)
++ .arg(ex.what());
++ stopChannel();
++ }
++}
++
++void
++PingChannel::socketReadCallback(boost::system::error_code ec, size_t length) {
++ {
++ MultiThreadingLock lock(*mutex_);
++ if (stopping_) {
++ return;
++ }
++ }
++
++ if (ec) {
++ if (ec.value() == boost::asio::error::operation_aborted) {
++ // IO service has been stopped and the connection is probably
++ // going to be shutting down.
++ return;
++ } else if ((ec.value() == boost::asio::error::try_again) ||
++ (ec.value() == boost::asio::error::would_block)) {
++ // We got EWOULDBLOCK or EAGAIN which indicates that we may be able to
++ // read something from the socket on the next attempt. Just make sure
++ // we don't try to read anything now in case there is any garbage
++ // passed in length.
++ length = 0;
++ } else {
++ // Anything else is fatal for the socket.
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_SOCKET_READ_FAILED)
++ .arg(ec.message());
++ stopChannel();
++ return;
++ }
++ }
++
++ // Unpack the reply and pass it to the reply callback.
++ ICMPMsgPtr reply;
++ if (length > 0) {
++ {
++ try {
++ MultiThreadingLock lock(*mutex_);
++ reply = ICMPMsg::unpack(getInputBufData(), getInputBufSize());
++ if (reply->getType() == ICMPMsg::ECHO_REPLY) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED)
++ .arg(reply->getSource())
++ .arg(reply->getId())
++ .arg(reply->getSequence());
++ }
++ } catch (const std::exception& ex) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC,
++ PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED)
++ .arg(ex.what());
++ }
++ }
++ }
++
++ {
++ MultiThreadingLock lock(*mutex_);
++ reading_ = false;
++ }
++
++ if (reply) {
++ (reply_received_cb_)(reply);
++ }
++
++ // Start the next read.
++ doRead();
++}
++
++void
++PingChannel::startSend() {
++ MultiThreadingLock lock(*mutex_);
++ if (canSend()) {
++ // Post the call to sendNext to the IOService.
++ // This ensures its carried out on a thread
++ // associated with the channel's IOService
++ // not the thread invoking this function.
++ auto f = [](PingChannelPtr ptr) { ptr->sendNext(); };
++ io_service_->post(std::bind(f, shared_from_this()));
++ }
++}
++
++void
++PingChannel::startRead() {
++ MultiThreadingLock lock(*mutex_);
++ if (canRead()) {
++ // Post the call to doRead to the IOService.
++ // This ensures its carried out on a thread
++ // associated with the channel's IOService
++ // not the thread invoking this function.
++ auto f = [](PingChannelPtr ptr) { ptr->doRead(); };
++ io_service_->post(std::bind(f, shared_from_this()));
++ }
++}
++
++void
++PingChannel::sendNext() {
++ try {
++ MultiThreadingLock lock(*mutex_);
++ if (!canSend()) {
++ // Can't send right now, get out.
++ return;
++ }
++
++ // Fetch the next one to send.
++ IOAddress target("0.0.0.0");
++ if (!((next_to_send_cb_)(target))) {
++ // Nothing to send.
++ return;
++ }
++
++ // Have an target IP, build an ECHO REQUEST for it.
++ sending_ = true;
++ ICMPMsgPtr next_echo(new ICMPMsg());
++ next_echo->setType(ICMPMsg::ECHO_REQUEST);
++ next_echo->setDestination(target);
++
++ uint32_t instance_num = nextEchoInstanceNum();
++ next_echo->setId(static_cast<uint16_t>(instance_num >> 16));
++ next_echo->setSequence(static_cast<uint16_t>(instance_num & 0x0000FFFF));
++
++ // Get packed wire-form.
++ ICMPPtr echo_icmp = next_echo->pack();
++
++ // Create instance of the callback. It is safe to pass the
++ // local instance of the callback, because the underlying
++ // std functions make copies as needed.
++ SocketCallback cb(std::bind(&PingChannel::socketWriteCallback,
++ shared_from_this(),
++ next_echo,
++ ph::_1, // error
++ ph::_2)); // bytes_transferred
++
++ ICMPEndpoint target_endpoint(target);
++ asyncSend(echo_icmp.get(), sizeof(struct icmp), &target_endpoint, cb);
++ } catch (const std::exception& ex) {
++ // Normal IO failures should be passed to the callback. A failure here
++ // indicates the call to asyncSend() itself failed.
++ LOG_ERROR(ping_check_logger, PING_CHECK_UNEXPECTED_WRITE_ERROR)
++ .arg(ex.what());
++ stopChannel();
++ return;
++ }
++}
++
++void
++PingChannel::socketWriteCallback(ICMPMsgPtr echo, boost::system::error_code ec,
++ size_t length) {
++ {
++ MultiThreadingLock lock(*mutex_);
++ if (stopping_) {
++ return;
++ }
++ }
++
++ if (single_threaded_) {
++ try {
++ // Clear the IO ready marker.
++ watch_socket_->clearReady();
++ } catch (const std::exception& ex) {
++ // This can only happen if the WatchSocket's select_fd has been
++ // compromised which is a programmatic error. We'll log the error
++ // here, then continue on and process the IO result we were given.
++ // WatchSocket issue will resurface on the next send as a closed
++ // fd in markReady() rather than fail out of this callback.
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR)
++ .arg(ex.what());
++ }
++ }
++
++ // Handle an error. Note we can't use a case statement as some values
++ // on some OSes are the same (e.g. try_again and would_block) which causes
++ // duplicate case compilation errors.
++ bool send_failed = false;
++ if (ec) {
++ auto error_value = ec.value();
++ if (error_value == boost::asio::error::operation_aborted) {
++ // IO service has been stopped and the connection is probably
++ // going to be shutting down.
++ return;
++ } else if ((error_value == boost::asio::error::try_again) ||
++ (error_value == boost::asio::error::would_block)) {
++ // We got EWOULDBLOCK or EAGAIN which indicates that we may be able to
++ // write something from the socket on the next attempt. Set the length
++ // to zero so we skip the completion callback.
++ length = 0;
++ } else if ((error_value == boost::asio::error::network_unreachable) ||
++ (error_value == boost::asio::error::host_unreachable) ||
++ (error_value == boost::asio::error::network_down)) {
++ // One of these implies an interface might be down, or there's no
++ // way to ping this network. Other networks might be working OK.
++ send_failed = true;
++ } else if (error_value == boost::asio::error::no_buffer_space) {
++ // Writing faster than the kernel will write them out.
++ send_failed = true;
++ } else if (error_value == boost::asio::error::access_denied) {
++ // Means the address we tried to ping is not allowed. Most likey a broadcast
++ // address.
++ send_failed = true;
++ } else {
++ // Anything else is fatal for the socket.
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED)
++ .arg(ec.message());
++ stopChannel();
++ return;
++ }
++ }
++
++ {
++ MultiThreadingLock lock(*mutex_);
++ sending_ = false;
++ }
++
++ if (send_failed) {
++ // Invoke the callback with send failed. This instructs the manager
++ // to treat the address as free to use.
++ LOG_ERROR(ping_check_logger, PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR)
++ .arg(echo->getDestination())
++ .arg(ec.message());
++ // Invoke the send completed callback.
++ (echo_sent_cb_)(echo, true);
++ } else if (length > 0) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_CHANNEL_ECHO_REQUEST_SENT)
++ .arg(echo->getDestination())
++ .arg(echo->getId())
++ .arg(echo->getSequence());
++ // Invoke the send completed callback.
++ (echo_sent_cb_)(echo, false);
++ }
++
++ // Schedule the next send.
++ sendNext();
++}
++
++size_t
++PingChannel::getInputBufSize() const {
++ return (input_buf_.size());
++}
++
++unsigned char*
++PingChannel::getInputBufData() {
++ if (input_buf_.empty()) {
++ isc_throw(InvalidOperation,
++ "PingChannel::getInputBufData() - cannot access empty buffer");
++ }
++
++ return (input_buf_.data());
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/ping_channel.h b/src/hooks/dhcp/ping_check/ping_channel.h
+new file mode 100644
+index 0000000000..ad798188e3
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_channel.h
+@@ -0,0 +1,371 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CHANNEL_H
++#define PING_CHANNEL_H
++
++#include <asiolink/asio_wrapper.h>
++#include <asiolink/io_address.h>
++#include <asiolink/io_service.h>
++#include <util/watch_socket.h>
++#include <icmp_msg.h>
++#include <icmp_socket.h>
++
++#include <boost/scoped_ptr.hpp>
++#include <boost/enable_shared_from_this.hpp>
++
++#include <iostream>
++#include <mutex>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Type of the function implementing a callback invoked by the
++/// @c SocketCallback functor.
++typedef std::function<void(boost::system::error_code ec, size_t length)> SocketCallbackFunction;
++
++/// @brief Functor associated with the socket object.
++///
++/// This functor calls a callback function specified in the constructor.
++class SocketCallback {
++public:
++ /// @brief Constructor.
++ ///
++ /// @param socket_callback Callback to be invoked by the functor upon
++ /// an event associated with the socket.
++ explicit inline SocketCallback(SocketCallbackFunction socket_callback)
++ : callback_(socket_callback) {
++ };
++
++ /// @brief Operator called when event associated with a socket occurs.
++ ///
++ /// This operator returns immediately when received @c boost::system::error_code
++ /// is equal to @c boost::asio::error::operation_aborted.
++ ///
++ /// @param ec Error code.
++ /// @param length Data length.
++ inline void operator()(boost::system::error_code ec, size_t length = 0) {
++ if (ec.value() == boost::asio::error::operation_aborted) {
++ return;
++ }
++
++ callback_(ec, length);
++ };
++
++private:
++ /// @brief Supplied callback.
++ SocketCallbackFunction callback_;
++};
++
++/// @brief Socket type for performing ICMP socket IO.
++typedef ICMPSocket<SocketCallback> PingSocket;
++
++/// @brief Defines a pointer to PingSocket.
++typedef boost::shared_ptr<PingSocket> PingSocketPtr;
++
++/// @brief Function type for callback that fetches next IOAddress to ping.
++typedef std::function<bool(asiolink::IOAddress& target)> NextToSendCallback;
++
++/// @brief Function type for callback to invoke upon ECHO send completion.
++typedef std::function<void(ICMPMsgPtr& echo, bool send_failed)> EchoSentCallback;
++
++/// @brief Function type for callback to invoke when an ICMP reply has been
++/// received.
++typedef std::function<void(ICMPMsgPtr& reply)> ReplyReceivedCallback;
++
++/// @brief Function type for callback to invoke when the channel has shutdown.
++typedef std::function<void()> ShutdownCallback;
++
++/// @brief Provides thread-safe ICMP ECHO REQUEST/ECHO REPLY service
++///
++/// PingChannel uses a @ref PingSocket to send out ECHO REQUESTs and
++/// receive ICMP replies. It is thread-safe and can be driven either
++/// with a single-threaded IOService or a multi-threaded
++/// IOServiceThreadPool. It uses series of callbacks to perpetually
++/// send requests to target addresses and feed back replies received:
++///
++/// -# next_to_send_cb_ - callback to invoke to fetch the next address to ping
++/// -# echo_sent_cb_ - callback to invoke when an ECHO REQUEST has been sent out
++/// -# reply_received_cb_ - callback to invoke when an ICMP reply has been received.
++/// -# channel_shutdown_cb_ - callback to invoke when the channel has shutdown
++///
++/// Callback handlers are supplied via the PingChannel constructor. Higher order
++/// functions are provided, that once instantiated, can be used by calling layers
++/// to control the channel (e.g. open the channel, initiate reading, initiate
++/// writing, and close the channel).
++///
++/// @note Callbacks handlers must be thread-safe if the channel is
++/// driven by an IOServiceThreadPool.
++///
++class PingChannel : public boost::enable_shared_from_this<PingChannel> {
++public:
++ /// @brief Constructor
++ ///
++ /// Instantiates the channel with its socket closed.
++ ///
++ /// @param io_service pointer to the IOService instance that will manage
++ /// the channel's IO. Must not be empty
++ /// @param next_to_send_cb callback to invoke to fetch the next IOAddress
++ /// to ping
++ /// @param echo_sent_cb callback to invoke when an ECHO send has completed
++ /// @param reply_received_cb callback to invoke when an ICMP reply has been
++ /// received. This callback is passed all inbound ICMP messages (e.g. ECHO
++ /// REPLY, UNREACHABLE, etc...)
++ /// @param shutdown_cb callback to invoke when the channel has shutdown due
++ /// to an error
++ ///
++ /// @throw BadValue if io_service is empty.
++ PingChannel(asiolink::IOServicePtr& io_service,
++ NextToSendCallback next_to_send_cb,
++ EchoSentCallback echo_sent_cb,
++ ReplyReceivedCallback reply_received_cb,
++ ShutdownCallback shutdown_cb = ShutdownCallback());
++
++ /// @brief Destructor
++ ///
++ /// Closes the socket if its open.
++ virtual ~PingChannel();
++
++ /// @brief Opens the socket for communications
++ ///
++ /// (Re)Creates the @ref PingSocket instance and opens it.
++ ///
++ /// @throw Unexpected if the open fails.
++ void open();
++
++ /// @brief Indicates whether or not the channel socket is open.
++ ///
++ /// @return true if the socket is open.
++ bool isOpen() const;
++
++ // @brief Schedules the next send.
++ //
++ // If the socket is not currently sending it posts a call to @c sendNext()
++ // to the channel's IOService.
++ virtual void startSend();
++
++ // @brief Schedules the next read.
++ //
++ // If the socket is not currently reading it posts a call to @c doRead()
++ // to the channel's IOService.
++ void startRead();
++
++ /// @brief Closes the channel's socket.
++ void close();
++
++ /// @brief Fetches the channel's IOService
++ ///
++ /// @return pointer to the IOService.
++ asiolink::IOServicePtr getIOService() {
++ return (io_service_);
++ }
++
++protected:
++ /// @brief Receive data on the socket asynchronously
++ ///
++ /// Calls the underlying socket's asyncReceive() method to read a
++ /// packet of data from a remote endpoint. Arrival of the data is signalled
++ /// via a call to the callback function.
++ ///
++ /// This virtual function is provided as means to inject errors during
++ /// read operations to facilitate testing.
++ ///
++ /// @param data buffer to receive incoming message
++ /// @param length length of the data buffer
++ /// @param offset offset into buffer where data is to be put
++ /// @param endpoint source of the communication
++ /// @param callback callback object
++ virtual void asyncReceive(void* data, size_t length, size_t offset,
++ asiolink::IOEndpoint* endpoint, SocketCallback& callback);
++
++ /// @brief Send data on the socket asynchronously
++ ///
++ /// Calls the underlying socket's asyncSend() method to send a
++ /// packet of data from a remote endpoint. Arrival of the data is signalled
++ /// via a call to the callback function.
++ ///
++ /// This virtual function is provided as means to inject errors during
++ /// write operations to facilitate testing.
++ ///
++ /// @param data buffer containing the data to send
++ /// @param length length of the data buffer
++ /// @param endpoint destination of the communication
++ /// @param callback callback object
++ virtual void asyncSend(void* data, size_t length, asiolink::IOEndpoint* endpoint,
++ SocketCallback& callback);
++
++protected:
++ /// @brief Initiates an asynchronous socket read.
++ ///
++ /// If the channel is able to read (is open, not stopping and not
++ /// currently reading) it invokes @ref PingSocket::asyncReceive()
++ /// otherwise it simply returns. If the call to asyncReceive() fails
++ /// it calls @c stopChannel() otherwise, when it completes it will
++ /// invoke @c socketReadCallback().
++ void doRead();
++
++ /// @brief Socket read completion callback
++ ///
++ /// Invoked when PingSocket::asyncRead() completes.
++ /// Upon read success and data received:
++ ///
++ /// -# Unpacks the wire data
++ /// -# Pass the resultant ICMPMsg to reply received callback
++ /// -# start next read
++ ///
++ /// On error conditions:
++ ///
++ /// -# Operation aborted: socket is shutting down, simply return
++ /// -# Operation would block/try again: start a new read
++ /// -# Any other error, shut down the channel
++ ///
++ /// @param ec error code indicating either success or the error encountered
++ /// @param length number of bytes read
++ void socketReadCallback(boost::system::error_code ec, size_t length);
++
++ /// @brief Initiates sending the next ECHO REQUEST
++ ///
++ /// If the channel is able to send (i.e is open, not stopping and not
++ /// currently writing):
++ /// -# Invoke next to send callback to fetch the next target IP address
++ /// -# If there is no next target, return
++ /// -# Construct the ECHO REQUEST for the target and pack it into wire form
++ /// -# Begin sending the request by passing to @c PingSocket::asyncSend()
++ /// -# If the asyncSend() call fails shutdown the channel, otherwise when
++ /// it completes it invokes @c socketWriteCallback().
++ virtual void sendNext();
++
++ /// @brief Socket write completion callback
++ ///
++ /// Invoked when PingSocket::asyncWrite() completes.
++ /// Upon write success:
++ ///
++ /// -# Pass the ECHO REQUEST (i.e. echo_sent) to echo sent callback
++ /// -# start next write
++ ///
++ /// On error conditions:
++ ///
++ /// -# Operation aborted: socket is shutting down, simply return
++ /// -# Operation would block/try again: start a new write
++ /// -# Any other error, shut down the channel
++ ///
++ /// @param echo_sent ECHO REQUEST that was written (or attempted to be
++ /// written)
++ /// @param ec error code indicating either success or the error encountered
++ /// @param length number of bytes written
++ void socketWriteCallback(ICMPMsgPtr echo_sent, boost::system::error_code ec,
++ size_t length);
++
++ /// @brief Closes the socket channel and invokes the shutdown callback.
++ ///
++ /// This function is invoked to notify the calling layer that the socket
++ /// has encountered an unrecoverable error and is stopping operations.
++ void stopChannel();
++
++ /// @brief returns the next unique ECHO instance number.
++ ///
++ /// This method generates and returns the next ECHO instance
++ /// number by incrementing the current value. It is a strictly
++ /// monotonously increasing value beginning at 0x00010001.
++ /// At roll over it resets to 0x00010001.
++ ///
++ /// Must be called in a thread-safe context
++ ///
++ /// @return the next unique instance number.
++ static uint32_t nextEchoInstanceNum();
++
++ /// @brief Indicates whether or not a send can be initiated.
++ ///
++ /// Must be called in a thread-safe context
++ ///
++ /// @return True if the socket is open, is not attempting to stop, and is
++ /// not currently sending.
++ bool canSend() {
++ return (socket_ && socket_->isOpen() && !stopping_ && !sending_);
++ }
++
++ /// @brief Indicates whether or not a read can be initiated.
++ ///
++ /// Must be called in a thread-safe context
++ ///
++ /// @return True if the socket is open, is not attempting to stop, and is
++ /// not currently reading.
++ bool canRead() {
++ return (socket_ && socket_->isOpen() && !stopping_ && !reading_);
++ }
++
++ /// @brief Returns input buffer size.
++ ///
++ /// Must be called in a thread-safe context
++ ///
++ /// @return size of the input buf
++ size_t getInputBufSize() const;
++
++ /// @brief Returns pointer to the first byte of the input buffer.
++ ///
++ /// Must be called in a thread-safe context
++ ///
++ /// @return pointer to the data buffer
++ /// @throw InvalidOperation if called when the buffer is empty.
++ unsigned char* getInputBufData();
++
++ /// @brief IOService instance the drives socket IO
++ asiolink::IOServicePtr io_service_;
++
++ /// @brief Callback to invoke to fetch the next address to ping.
++ NextToSendCallback next_to_send_cb_;
++
++ /// @brief Callback to invoke when an ECHO write has completed.
++ EchoSentCallback echo_sent_cb_;
++
++ /// @brief Callback to invoke when an ICMP reply has been received.
++ ReplyReceivedCallback reply_received_cb_;
++
++ /// @brief Callback to invoke when the channel has shutdown.
++ ShutdownCallback shutdown_cb_;
++
++ /// @brief Socket through which to ping.
++ PingSocketPtr socket_;
++
++ /// @brief Buffer to hold the contents for most recent socket read.
++ std::vector<uint8_t> input_buf_;
++
++ /// @brief Retains the endpoint from which the most recent reply was received.
++ ICMPEndpoint reply_endpoint_;
++
++ /// @brief Indicates whether or not the socket has a read in progress.
++ bool reading_;
++
++ /// @brief Indicates whether or not the socket has a write in progress.
++ bool sending_;
++
++ /// @brief Indicates whether or not the channel has been told to stop.
++ bool stopping_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++
++ /// @brief True if channel was opened in single-threaded mode, false
++ /// otherwise.
++ bool single_threaded_;
++
++ /// @brief Pointer to WatchSocket instance supplying the "select-fd".
++ util::WatchSocketPtr watch_socket_;
++
++ /// @brief WatchSocket fd registered with IfaceMgr.
++ int registered_write_fd_;
++
++ /// @brief ICMPSocket fd registered with IfaceMgr.
++ int registered_read_fd_;
++};
++
++/// @brief Defines a smart pointer to PingChannel
++typedef boost::shared_ptr<PingChannel> PingChannelPtr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/ping_check.dox b/src/hooks/dhcp/ping_check/ping_check.dox
+new file mode 100644
+index 0000000000..a7fbe839c0
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check.dox
+@@ -0,0 +1,44 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/**
++
++@mainpage Kea Ping Check Hooks Library
++
++Welcome to Kea Ping Check Hooks Library. This documentation is
++addressed at developers who are interested in internal operation of the
++library. This file provides information needed to understand and perhaps
++extend this library.
++
++This documentation is stand-alone: you should have read and
++understood <a href="https://reports.kea.isc.org/dev_guide/">Kea
++Developer's Guide</a> and in particular its section about hooks: <a
++href="https://reports.kea.isc.org/dev_guide/df/d46/hooksdgDevelopersGuide.html">
++Hooks Developer's Guide</a>.
++
++@section cbPingCheckOverview Overview
++The @c ping_check hooks library provides the ability for kea-dhcp4 to carry
++out an ICMP ECHO test of a candidate IP address prior to sending that address to
++a DHCPv4 client in a DHCPOFFER message.
++
++@section cbPingCheckInternals Library Internals
++
++In addition to the requisite @ref load() and @ref unload() functions, the library
++implements the following callouts:
++
++- @ref dhcp4_srv_configured() - schedules a (re)start of the ICMP IO layer
++- @ref lease4_offer() - handles requests from kea-dhcp4 core to initiate a ping check
++for a candidate lease
++
++The load() function instantiates an instance of @ref isc::ping_check::PingCheckMgr.
++This class is the top level object that provides configuration processing and supervises
++the execution of ping checks.
++
++@section cbPingCheckMTCompatibility Multi-Threading Compatibility
++
++The @c ping_check hooks library requires multi-threading.
++
++*/
+diff --git a/src/hooks/dhcp/ping_check/ping_check_callouts.cc b/src/hooks/dhcp/ping_check/ping_check_callouts.cc
+new file mode 100644
+index 0000000000..ae006359be
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_callouts.cc
+@@ -0,0 +1,240 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <asiolink/io_service_mgr.h>
++#include <database/audit_entry.h>
++#include <dhcpsrv/cfgmgr.h>
++#include <ping_check_log.h>
++#include <ping_check_mgr.h>
++#include <hooks/hooks.h>
++#include <process/daemon.h>
++#include <string>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief PingCheckMgr singleton
++PingCheckMgrPtr mgr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::log;
++using namespace isc::data;
++using namespace isc::db;
++using namespace isc::dhcp;
++using namespace isc::ping_check;
++using namespace isc::hooks;
++using namespace isc::process;
++using namespace std;
++
++// Functions accessed by the hooks framework use C linkage to avoid the name
++// mangling that accompanies use of the C++ compiler as well as to avoid
++// issues related to namespaces.
++extern "C" {
++
++/// @brief dhcp4_srv_configured implementation.
++///
++/// @param handle callout handle.
++int dhcp4_srv_configured(CalloutHandle& handle) {
++ try {
++ SrvConfigPtr server_config;
++ handle.getArgument("server_config", server_config);
++ mgr->updateSubnetConfig(server_config);
++
++ NetworkStatePtr network_state;
++ handle.getArgument("network_state", network_state);
++
++ // Schedule a start of the services. This ensures we begin after
++ // the dust has settled and Kea MT mode has been firmly established.
++ mgr->startService(network_state);
++ IOServiceMgr::instance().registerIOService(mgr->getIOService());
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED)
++ .arg(ex.what());
++
++ handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
++ ostringstream os;
++ os << "Error: " << ex.what();
++ string error(os.str());
++ handle.setArgument("error", error);
++ return (1);
++ }
++
++ return (0);
++}
++
++/// @brief cb4_updated callout implementation.
++///
++/// If it detects that any subnets were altered by the update it
++/// replaces the subnet cache contents. If any of the subnets
++/// fail to parse, the error is logged and the function returns
++/// a non-zero value.
++///
++/// @param handle CalloutHandle.
++///
++/// @return 0 upon success, 1 otherwise
++int cb4_updated(CalloutHandle& handle) {
++ AuditEntryCollectionPtr audit_entries;
++ handle.getArgument("audit_entries", audit_entries);
++
++ auto const& object_type_idx = audit_entries->get<AuditEntryObjectTypeTag>();
++ auto range = object_type_idx.equal_range("dhcp4_subnet");
++ if (std::distance(range.first, range.second)) {
++ try {
++ // Server config has been committed, so use the current configuration.
++ mgr->updateSubnetConfig(CfgMgr::instance().getCurrentCfg());
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_CB4_UPDATE_FAILED)
++ .arg(ex.what());
++ return (1);
++ }
++ }
++
++ return (0);
++}
++
++/// @brief lease4_offer callout implementation.
++///
++/// @param handle callout handle.
++int lease4_offer(CalloutHandle& handle) {
++ CalloutHandle::CalloutNextStep status = handle.getStatus();
++ if (status == CalloutHandle::NEXT_STEP_DROP ||
++ status == CalloutHandle::NEXT_STEP_SKIP) {
++ return (0);
++ }
++
++ Pkt4Ptr query4;
++ Lease4Ptr lease4;
++ ParkingLotHandlePtr parking_lot;
++ try {
++ // Get all arguments available for the leases4_committed hook point.
++ // If any of these arguments is not available this is a programmatic
++ // error. An exception will be thrown which will be caught by the
++ // caller and logged.
++ handle.getArgument("query4", query4);
++
++ Lease4CollectionPtr leases4;
++ handle.getArgument("leases4", leases4);
++
++ uint32_t offer_lifetime;
++ handle.getArgument("offer_lifetime", offer_lifetime);
++
++ Lease4Ptr old_lease;
++ handle.getArgument("old_lease", old_lease);
++
++ if (query4->getType() != DHCPDISCOVER) {
++ isc_throw(InvalidOperation, "query4 is not a DHCPDISCOVER");
++ }
++
++ if (!leases4) {
++ isc_throw(InvalidOperation, "leases4 is null");
++ }
++
++ if (!leases4->empty()) {
++ lease4 = (*leases4)[0];
++ }
++
++ if (!lease4) {
++ isc_throw(InvalidOperation, "leases4 is empty, no lease to check");
++ }
++
++ // Fetch the parking lot. If it's empty the server is not employing
++ // parking, which is fine.
++ // Create a reference to the parked packet. This signals that we have a
++ // stake in unparking it.
++ parking_lot = handle.getParkingLotHandlePtr();
++ if (parking_lot) {
++ parking_lot->reference(query4);
++ }
++
++ // Get configuration based on the lease's subnet.
++ auto const& config = mgr->getScopedConfig(lease4);
++
++ // Call shouldPing() to determine if we should ping check or not.
++ // - status == PARK - ping check it
++ // - status == CONTINUE - check not needed, release DHCPOFFER to client
++ // - status == DROP - duplicate check, drop the duplicate DHCPOFFER
++ status = mgr->shouldPing(lease4, query4, old_lease, config);
++ handle.setStatus(status);
++ if (status == CalloutHandle::NEXT_STEP_PARK) {
++ mgr->startPing(lease4, query4, parking_lot, config);
++ } else {
++ // Dereference the parked packet. This releases our stake in it.
++ if (parking_lot) {
++ parking_lot->dereference(query4);
++ }
++ }
++
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_LEASE4_OFFER_FAILED)
++ .arg(query4 ? query4->getLabel() : "<no query>")
++ .arg(lease4 ? lease4->addr_.toText() : "<no lease>")
++ .arg(ex.what());
++ // Make sure we dereference.
++ if (parking_lot) {
++ parking_lot->dereference(query4);
++ }
++
++ return (1);
++ }
++
++ return (0);
++}
++
++/// @brief This function is called when the library is loaded.
++///
++/// @param handle library handle
++/// @return 0 when initialization is successful, 1 otherwise
++int load(LibraryHandle& handle) {
++ try {
++ // Make the hook library only loadable by kea-dhcp4.
++ const string& proc_name = Daemon::getProcName();
++ if (proc_name != "kea-dhcp4") {
++ isc_throw(isc::Unexpected, "Bad process name: " << proc_name
++ << ", expected kea-dhcp4");
++ }
++
++ // Instantiate the manager singleton.
++ mgr.reset(new PingCheckMgr());
++
++ // Configure the manager using the hook library's parameters.
++ ConstElementPtr json = handle.getParameters();
++ mgr->configure(json);
++ } catch (const exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_LOAD_ERROR)
++ .arg(ex.what());
++ return (1);
++ }
++
++ LOG_INFO(ping_check_logger, PING_CHECK_LOAD_OK);
++ return (0);
++}
++
++/// @brief This function is called when the library is unloaded.
++///
++/// @return always 0.
++int unload() {
++ if (mgr) {
++ IOServiceMgr::instance().unregisterIOService(mgr->getIOService());
++ mgr.reset();
++ }
++ LOG_INFO(ping_check_logger, PING_CHECK_UNLOAD);
++ return (0);
++}
++
++/// @brief This function is called to retrieve the multi-threading compatibility.
++///
++/// @return 1 which means compatible with multi-threading.
++int multi_threading_compatible() {
++ return (1);
++}
++
++} // end extern "C"
+diff --git a/src/hooks/dhcp/ping_check/ping_check_config.cc b/src/hooks/dhcp/ping_check/ping_check_config.cc
+new file mode 100644
+index 0000000000..a1c69da61e
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_config.cc
+@@ -0,0 +1,98 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <ping_check_config.h>
++
++using namespace isc;
++using namespace isc::data;
++using namespace isc::dhcp;
++
++namespace isc {
++namespace ping_check {
++
++const data::SimpleKeywords
++PingCheckConfig::CONFIG_KEYWORDS =
++{
++ { "enable-ping-check", Element::boolean },
++ { "min-ping-requests", Element::integer },
++ { "reply-timeout", Element::integer },
++ { "ping-cltt-secs", Element::integer},
++ { "ping-channel-threads", Element::integer}
++};
++
++PingCheckConfig::PingCheckConfig() :
++ enable_ping_check_(true),
++ min_ping_requests_(1),
++ reply_timeout_(100),
++ ping_cltt_secs_(60),
++ ping_channel_threads_(0) {
++}
++
++void
++PingCheckConfig::parse(data::ConstElementPtr config) {
++ // Use a local instance to collect values. This way we
++ // avoid corrupting current values if there are any errors.
++ PingCheckConfig local;
++
++ // Note checkKeywords() will throw DhcpConfigError if there is a problem.
++ SimpleParser::checkKeywords(CONFIG_KEYWORDS, config);
++ ConstElementPtr value = config->get("enable-ping-check");
++ if (value) {
++ local.setEnablePingCheck(value->boolValue());
++ }
++
++ value = config->get("min-ping-requests");
++ if (value) {
++ int64_t val = value->intValue();
++ if (val <= 0) {
++ isc_throw(DhcpConfigError, "invalid min-ping-requests: '"
++ << val << "', must be greater than 0");
++ }
++
++ local.setMinPingRequests(static_cast<size_t>(val));
++ }
++
++ value = config->get("reply-timeout");
++ if (value) {
++ int64_t val = value->intValue();
++ if (val <= 0) {
++ isc_throw(DhcpConfigError, "invalid reply-timeout: '"
++ << val << "', must be greater than 0");
++ }
++
++ local.setReplyTimeout(static_cast<size_t>(val));
++ }
++
++ value = config->get("ping-cltt-secs");
++ if (value) {
++ int64_t val = value->intValue();
++ if (val < 0) {
++ isc_throw(DhcpConfigError, "invalid ping-cltt-secs: '"
++ << val << "', cannot be less than 0");
++ }
++
++ local.setPingClttSecs(static_cast<size_t>(val));
++ }
++
++ value = config->get("ping-channel-threads");
++ if (value) {
++ int64_t val = value->intValue();
++ if (val < 0) {
++ isc_throw(DhcpConfigError, "invalid ping-channel-threads: '"
++ << val << "', cannot be less than 0");
++ }
++
++ local.setPingChannelThreads(static_cast<size_t>(val));
++ }
++
++ // All values good, copy from local instance.
++ *this = local;
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/ping_check_config.h b/src/hooks/dhcp/ping_check/ping_check_config.h
+new file mode 100644
+index 0000000000..9fd23eba59
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_config.h
+@@ -0,0 +1,134 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CHECK_CONFIG_H
++#define PING_CHECK_CONFIG_H
++
++#include <cc/data.h>
++#include <cc/simple_parser.h>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Houses the Ping check configuration parameters for a single scope
++/// (e.g. global, subnet...);
++class PingCheckConfig {
++public:
++ /// @brief List of valid parameters and expected types.
++ static const data::SimpleKeywords CONFIG_KEYWORDS;
++
++ /// @brief Constructor
++ PingCheckConfig();
++
++ /// @brief Destructor
++ ~PingCheckConfig() = default;
++
++ /// @brief Extracts member values from an Element::map
++ ///
++ /// @param config map of configuration parameters
++ ///
++ /// @throw BadValue if invalid values are detected.
++ void parse(data::ConstElementPtr config);
++
++ /// @brief Fetches the value of enable-ping-check
++ ///
++ /// @return boolean value of enable-ping-check
++ bool getEnablePingCheck() const {
++ return (enable_ping_check_);
++ };
++
++ /// @brief Sets the value of enable-ping-check
++ ///
++ /// @param value new value for enable-ping-check
++ void setEnablePingCheck(bool value) {
++ enable_ping_check_ = value;
++ }
++
++ /// @brief Fetches the value of min-ping-requests
++ ///
++ /// @return integer value of min-ping-requests
++ uint32_t getMinPingRequests() const {
++ return (min_ping_requests_);
++ };
++
++ /// @brief Sets the value of min-ping-requests
++ ///
++ /// @param value new value for min-ping-requests
++ void setMinPingRequests(uint32_t value) {
++ min_ping_requests_ = value;
++ }
++
++ /// @brief Fetches the value of reply-timeout
++ ///
++ /// @return integer value of reply-timeout
++ uint32_t getReplyTimeout() const {
++ return (reply_timeout_);
++ }
++
++ /// @brief Sets the value of reply-timeout
++ ///
++ /// @param value new value for reply-timeout
++ void setReplyTimeout(uint32_t value) {
++ reply_timeout_ = value;
++ }
++
++ /// @brief Fetches the value of ping-cltt-secs
++ ///
++ /// @return integer value of ping-cltt-secs
++ uint32_t getPingClttSecs() const {
++ return (ping_cltt_secs_);
++ }
++
++ /// @brief Sets the value of ping-cltt-secs
++ ///
++ /// @param value new value for ping-cltt-secs
++ void setPingClttSecs(uint32_t value) {
++ ping_cltt_secs_ = value;
++ }
++
++ /// @brief Fetches the value of ping-channel-threads
++ ///
++ /// @return integer value of ping-channel-threads
++ uint32_t getPingChannelThreads() const {
++ return (ping_channel_threads_);
++ }
++
++ /// @brief Sets the value of ping-channel-threads
++ ///
++ /// @param value new value for ping-channel-threads
++ void setPingChannelThreads(uint32_t value) {
++ ping_channel_threads_ = value;
++ }
++
++private:
++ // @brief True if checking is enabled.
++ bool enable_ping_check_;
++
++ /// @brief minimum number of ECHO REQUESTs sent, without replies received,
++ /// required to declare an address free to offer.
++ uint32_t min_ping_requests_;
++
++ /// @brief maximum number of milliseconds to wait for an ECHO REPLY after
++ /// an ECHO REQUEST has been sent.
++ uint32_t reply_timeout_;
++
++ /// @brief minimum number of seconds that must elapse after the lease's CLTT
++ /// before a ping check will be conducted, when the client is the lease's
++ /// previous owner.
++ uint32_t ping_cltt_secs_;
++
++ /// @brief Number of threads to use if Kea core is multi-threaded.
++ /// Defaults to 0 (for now) which means follow core number of threads.
++ size_t ping_channel_threads_;
++};
++
++/// @brief Defines a shared pointer to a PingCheckConfig.
++typedef boost::shared_ptr<PingCheckConfig> PingCheckConfigPtr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/ping_check_log.cc b/src/hooks/dhcp/ping_check/ping_check_log.cc
+new file mode 100644
+index 0000000000..9e877ff9b5
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_log.cc
+@@ -0,0 +1,17 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <ping_check_log.h>
++
++namespace isc {
++namespace ping_check {
++
++isc::log::Logger ping_check_logger("ping-check-hooks");
++
++} // namespace ping_check
++} // namespace isc
+diff --git a/src/hooks/dhcp/ping_check/ping_check_log.h b/src/hooks/dhcp/ping_check/ping_check_log.h
+new file mode 100644
+index 0000000000..22e0fca953
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_log.h
+@@ -0,0 +1,23 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CHECK_LOG_H
++#define PING_CHECK_LOG_H
++
++#include <log/logger_support.h>
++#include <log/macros.h>
++#include <log/log_dbglevels.h>
++#include <ping_check_messages.h>
++#include <iostream>
++
++namespace isc {
++namespace ping_check {
++
++extern isc::log::Logger ping_check_logger;
++
++} // end of namespace ping_check
++} // end of namespace isc
++#endif
+diff --git a/src/hooks/dhcp/ping_check/ping_check_messages.cc b/src/hooks/dhcp/ping_check/ping_check_messages.cc
+new file mode 100644
+index 0000000000..7dea2c2397
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_messages.cc
+@@ -0,0 +1,99 @@
++// File created from src/hooks/dhcp/ping_check/ping_check_messages.mes
++
++#include <cstddef>
++#include <log/message_types.h>
++#include <log/message_initializer.h>
++
++extern const isc::log::MessageID PING_CHECK_CB4_UPDATE_FAILED = "PING_CHECK_CB4_UPDATE_FAILED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED = "PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_ECHO_REQUEST_SENT = "PING_CHECK_CHANNEL_ECHO_REQUEST_SENT";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED = "PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR = "PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_CLOSED = "PING_CHECK_CHANNEL_SOCKET_CLOSED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR = "PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_OPENED = "PING_CHECK_CHANNEL_SOCKET_OPENED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_READ_FAILED = "PING_CHECK_CHANNEL_SOCKET_READ_FAILED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED = "PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_STOP = "PING_CHECK_CHANNEL_STOP";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR = "PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR";
++extern const isc::log::MessageID PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR = "PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR";
++extern const isc::log::MessageID PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED = "PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED";
++extern const isc::log::MessageID PING_CHECK_DUPLICATE_CHECK = "PING_CHECK_DUPLICATE_CHECK";
++extern const isc::log::MessageID PING_CHECK_LEASE4_OFFER_FAILED = "PING_CHECK_LEASE4_OFFER_FAILED";
++extern const isc::log::MessageID PING_CHECK_LOAD_ERROR = "PING_CHECK_LOAD_ERROR";
++extern const isc::log::MessageID PING_CHECK_LOAD_OK = "PING_CHECK_LOAD_OK";
++extern const isc::log::MessageID PING_CHECK_MGR_CHANNEL_DOWN = "PING_CHECK_MGR_CHANNEL_DOWN";
++extern const isc::log::MessageID PING_CHECK_MGR_LEASE_FREE_TO_USE = "PING_CHECK_MGR_LEASE_FREE_TO_USE";
++extern const isc::log::MessageID PING_CHECK_MGR_NEXT_ECHO_SCHEDULED = "PING_CHECK_MGR_NEXT_ECHO_SCHEDULED";
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_ECHO_REPLY = "PING_CHECK_MGR_RECEIVED_ECHO_REPLY";
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY = "PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY";
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG = "PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG";
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG = "PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG";
++extern const isc::log::MessageID PING_CHECK_MGR_REPLY_RECEIVED_ERROR = "PING_CHECK_MGR_REPLY_RECEIVED_ERROR";
++extern const isc::log::MessageID PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED = "PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED";
++extern const isc::log::MessageID PING_CHECK_MGR_SEND_COMPLETED_ERROR = "PING_CHECK_MGR_SEND_COMPLETED_ERROR";
++extern const isc::log::MessageID PING_CHECK_MGR_STARTED = "PING_CHECK_MGR_STARTED";
++extern const isc::log::MessageID PING_CHECK_MGR_STARTED_SINGLE_THREADED = "PING_CHECK_MGR_STARTED_SINGLE_THREADED";
++extern const isc::log::MessageID PING_CHECK_MGR_START_PING_CHECK = "PING_CHECK_MGR_START_PING_CHECK";
++extern const isc::log::MessageID PING_CHECK_MGR_STOPPED = "PING_CHECK_MGR_STOPPED";
++extern const isc::log::MessageID PING_CHECK_MGR_STOPPING = "PING_CHECK_MGR_STOPPING";
++extern const isc::log::MessageID PING_CHECK_MGR_SUBNET_CONFIG_FAILED = "PING_CHECK_MGR_SUBNET_CONFIG_FAILED";
++extern const isc::log::MessageID PING_CHECK_PAUSE_FAILED = "PING_CHECK_PAUSE_FAILED";
++extern const isc::log::MessageID PING_CHECK_PAUSE_ILLEGAL = "PING_CHECK_PAUSE_ILLEGAL";
++extern const isc::log::MessageID PING_CHECK_PAUSE_PERMISSIONS_FAILED = "PING_CHECK_PAUSE_PERMISSIONS_FAILED";
++extern const isc::log::MessageID PING_CHECK_RESUME_FAILED = "PING_CHECK_RESUME_FAILED";
++extern const isc::log::MessageID PING_CHECK_UNEXPECTED_READ_ERROR = "PING_CHECK_UNEXPECTED_READ_ERROR";
++extern const isc::log::MessageID PING_CHECK_UNEXPECTED_WRITE_ERROR = "PING_CHECK_UNEXPECTED_WRITE_ERROR";
++extern const isc::log::MessageID PING_CHECK_UNLOAD = "PING_CHECK_UNLOAD";
++
++namespace {
++
++const char* values[] = {
++ "PING_CHECK_CB4_UPDATE_FAILED", "A subnet ping-check parameters failed to parse after being updated %1",
++ "PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED", "from address %1, id %2, sequence %3",
++ "PING_CHECK_CHANNEL_ECHO_REQUEST_SENT", "to address %1, id %2, sequence %3",
++ "PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED", "error occurred unpacking message %1, discarding it",
++ "PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR", "occurred trying to ping %1, error %2",
++ "PING_CHECK_CHANNEL_SOCKET_CLOSED", "ICMP socket has been closed.",
++ "PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR", "an attempt to close the ICMP socket failed %1",
++ "PING_CHECK_CHANNEL_SOCKET_OPENED", "ICMP socket been opened successfully.",
++ "PING_CHECK_CHANNEL_SOCKET_READ_FAILED", "socket read completed with an error %1",
++ "PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED", "socket write completed with an error %1",
++ "PING_CHECK_CHANNEL_STOP", "channel is stopping operations.",
++ "PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR", "an attempt to clear the WatchSocket associated with",
++ "PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR", "an attempt to close the WatchSocket associated with",
++ "PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED", "dhcp4_srv_configured callout failed %1",
++ "PING_CHECK_DUPLICATE_CHECK", "Ping check already in progress for %1, initiated by %2",
++ "PING_CHECK_LEASE4_OFFER_FAILED", "lease4_offer callout failed for query %1, lease address %2, reason %3",
++ "PING_CHECK_LOAD_ERROR", "loading Ping Check hooks library failed %1",
++ "PING_CHECK_LOAD_OK", "Ping Check hooks library loaded successfully.",
++ "PING_CHECK_MGR_CHANNEL_DOWN", "Ping Channel has shutdown, ping checking will be skipped",
++ "PING_CHECK_MGR_LEASE_FREE_TO_USE", "address %1 is free to use for %2",
++ "PING_CHECK_MGR_NEXT_ECHO_SCHEDULED", "for %1, scheduling ECHO_REQUEST %2 of %3",
++ "PING_CHECK_MGR_RECEIVED_ECHO_REPLY", "from %1, id %2, sequence %3",
++ "PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY", "from %1, id %2, sequence %3 received after reply-timeout expired",
++ "PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG", "for %1, id %2, sequence %3 received after reply-timeout expired",
++ "PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG", "for %1, id %2, sequence %3",
++ "PING_CHECK_MGR_REPLY_RECEIVED_ERROR", "an error occurred processing an ICMP reply message %1",
++ "PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED", "for %1, ECHO REQUEST %2 of %3, reply-timeout %4",
++ "PING_CHECK_MGR_SEND_COMPLETED_ERROR", "an error occurred in the send completion callback %1",
++ "PING_CHECK_MGR_STARTED", "ping channel operations are running, number of threads %1",
++ "PING_CHECK_MGR_STARTED_SINGLE_THREADED", "single-threaded ping channel operations are running",
++ "PING_CHECK_MGR_START_PING_CHECK", "for %1, initiated by %2",
++ "PING_CHECK_MGR_STOPPED", "channel operations have stopped",
++ "PING_CHECK_MGR_STOPPING", "ping channel operations are stopping",
++ "PING_CHECK_MGR_SUBNET_CONFIG_FAILED", "user-context for subnet id %1, contains invalid ping-check %2",
++ "PING_CHECK_PAUSE_FAILED", "Pausing ping channel operations failed %1",
++ "PING_CHECK_PAUSE_ILLEGAL", "Pausing ping channel operations not allowed %1",
++ "PING_CHECK_PAUSE_PERMISSIONS_FAILED", "Permissions check for ping-channel pause failed %1",
++ "PING_CHECK_RESUME_FAILED", "Resuming ping channel operations failed %1",
++ "PING_CHECK_UNEXPECTED_READ_ERROR", "could not start next socket read %1",
++ "PING_CHECK_UNEXPECTED_WRITE_ERROR", "could not start next socket write %1",
++ "PING_CHECK_UNLOAD", "Ping Check hooks library has been unloaded",
++ NULL
++};
++
++const isc::log::MessageInitializer initializer(values);
++
++} // Anonymous namespace
++
+diff --git a/src/hooks/dhcp/ping_check/ping_check_messages.h b/src/hooks/dhcp/ping_check/ping_check_messages.h
+new file mode 100644
+index 0000000000..9326c699e8
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_messages.h
+@@ -0,0 +1,50 @@
++// File created from src/hooks/dhcp/ping_check/ping_check_messages.mes
++
++#ifndef PING_CHECK_MESSAGES_H
++#define PING_CHECK_MESSAGES_H
++
++#include <log/message_types.h>
++
++extern const isc::log::MessageID PING_CHECK_CB4_UPDATE_FAILED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_ECHO_REQUEST_SENT;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_CLOSED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_OPENED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_READ_FAILED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_STOP;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR;
++extern const isc::log::MessageID PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR;
++extern const isc::log::MessageID PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED;
++extern const isc::log::MessageID PING_CHECK_DUPLICATE_CHECK;
++extern const isc::log::MessageID PING_CHECK_LEASE4_OFFER_FAILED;
++extern const isc::log::MessageID PING_CHECK_LOAD_ERROR;
++extern const isc::log::MessageID PING_CHECK_LOAD_OK;
++extern const isc::log::MessageID PING_CHECK_MGR_CHANNEL_DOWN;
++extern const isc::log::MessageID PING_CHECK_MGR_LEASE_FREE_TO_USE;
++extern const isc::log::MessageID PING_CHECK_MGR_NEXT_ECHO_SCHEDULED;
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_ECHO_REPLY;
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY;
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG;
++extern const isc::log::MessageID PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG;
++extern const isc::log::MessageID PING_CHECK_MGR_REPLY_RECEIVED_ERROR;
++extern const isc::log::MessageID PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED;
++extern const isc::log::MessageID PING_CHECK_MGR_SEND_COMPLETED_ERROR;
++extern const isc::log::MessageID PING_CHECK_MGR_STARTED;
++extern const isc::log::MessageID PING_CHECK_MGR_STARTED_SINGLE_THREADED;
++extern const isc::log::MessageID PING_CHECK_MGR_START_PING_CHECK;
++extern const isc::log::MessageID PING_CHECK_MGR_STOPPED;
++extern const isc::log::MessageID PING_CHECK_MGR_STOPPING;
++extern const isc::log::MessageID PING_CHECK_MGR_SUBNET_CONFIG_FAILED;
++extern const isc::log::MessageID PING_CHECK_PAUSE_FAILED;
++extern const isc::log::MessageID PING_CHECK_PAUSE_ILLEGAL;
++extern const isc::log::MessageID PING_CHECK_PAUSE_PERMISSIONS_FAILED;
++extern const isc::log::MessageID PING_CHECK_RESUME_FAILED;
++extern const isc::log::MessageID PING_CHECK_UNEXPECTED_READ_ERROR;
++extern const isc::log::MessageID PING_CHECK_UNEXPECTED_WRITE_ERROR;
++extern const isc::log::MessageID PING_CHECK_UNLOAD;
++
++#endif // PING_CHECK_MESSAGES_H
+diff --git a/src/hooks/dhcp/ping_check/ping_check_messages.mes b/src/hooks/dhcp/ping_check/ping_check_messages.mes
+new file mode 100644
+index 0000000000..21d407bedf
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_messages.mes
+@@ -0,0 +1,229 @@
++# Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++#
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++% PING_CHECK_CB4_UPDATE_FAILED A subnet ping-check parameters failed to parse after being updated %1
++This error message is emitted when an error occurs trying to parse a subnet
++ping-check parameters after the subnet was updated via configuration backend.
++This implies one or more of the parameters is invalid and must be corrected.
++
++% PING_CHECK_CHANNEL_ECHO_REPLY_RECEIVED from address %1, id %2, sequence %3
++Logged at debug log level 50.
++This debug message is issued when an ECHO REPLY has been received on
++the ping channel's ICMP socket.
++
++% PING_CHECK_CHANNEL_ECHO_REQUEST_SENT to address %1, id %2, sequence %3
++Logged at debug log level 50.
++This debug message is issued when an ECHO REQUEST has been written to the
++ping channel's ICMP socket.
++
++% PING_CHECK_CHANNEL_MALFORMED_PACKET_RECEIVED error occurred unpacking message %1, discarding it
++Logged at debug log level 40.
++This debug message is emitted when an ICMP packet has been received
++that could not be unpacked.
++
++% PING_CHECK_CHANNEL_NETWORK_WRITE_ERROR occurred trying to ping %1, error %2
++This error message occurs when an asynchronous write on the ICMP socket
++failed trying to send on the ping target's network. This may mean an interface
++is down or there is a configuration error. The lease address to ping and the
++type of the error are provided in the arguments.
++
++% PING_CHECK_CHANNEL_SOCKET_CLOSED ICMP socket has been closed.
++Logged at debug log level 40.
++This debug message is emitted when the ICMP socket for carrying out
++ping checks has been closed.
++
++% PING_CHECK_CHANNEL_SOCKET_CLOSE_ERROR an attempt to close the ICMP socket failed %1
++This error message is emitted when an unexpected error occurred
++while closing the ping check ICMP socket. The error detail is
++provided as an argument of the log message.
++
++% PING_CHECK_CHANNEL_SOCKET_OPENED ICMP socket been opened successfully.
++Logged at debug log level 40.
++This debug message is emitted when the ICMP socket for carrying out
++ping checks has been successfully opened.
++
++% PING_CHECK_CHANNEL_SOCKET_READ_FAILED socket read completed with an error %1
++This error message occurs when an asynchronous read on the ICMP socket
++failed. The details of the error are provided as an argument of the log
++message.
++
++% PING_CHECK_CHANNEL_SOCKET_WRITE_FAILED socket write completed with an error %1
++This error message occurs when an asynchronous write on the ICMP socket
++failed. The details of the error are provided as an argument of the log
++message.
++
++% PING_CHECK_CHANNEL_STOP channel is stopping operations.
++Logged at debug log level 40.
++This debug message indicates that the channel is stopping operations and
++closing the ICMP socket. The reason for stopping should be apparent in
++preceding log messages.
++
++% PING_CHECK_CHANNEL_WATCH_SOCKET_CLEAR_ERROR an attempt to clear the WatchSocket associated with
++the single-threaded ping-channel failed %1
++This error message is emitted when an unexpected error occurred
++while clearing the ready marker of the WatchSocket associated with
++the ping check channel. This can only occur when running in
++single-threaded mode. The error detail is provided as an argument
++of the log message.
++
++% PING_CHECK_CHANNEL_WATCH_SOCKET_CLOSE_ERROR an attempt to close the WatchSocket associated with
++the single-threaded ping-channel failed %1
++This error message is emitted when an unexpected error occurred
++while closing the WatchSocket associated with the ping check channel.
++This can only occur when running in single-threaded mode.
++The error detail is provided as an argument of the log message.
++
++% PING_CHECK_DHCP4_SRV_CONFIGURED_FAILED dhcp4_srv_configured callout failed %1
++This error message indicates an error during the Ping Check hook
++library dhcp4_srv_configured callout. The details of the error are
++provided as argument of the log message.
++
++% PING_CHECK_DUPLICATE_CHECK Ping check already in progress for %1, initiated by %2
++Logged at debug log level 40.
++This debug message is emitted when a duplicate request to test an address
++is received. When this occurs the duplicate test will be skipped and
++the associated DHCPOFFER will be dropped.
++
++% PING_CHECK_LEASE4_OFFER_FAILED lease4_offer callout failed for query %1, lease address %2, reason %3
++This error message indicates an error during the Ping Check hook
++library lease4_offer callout. The details of the error are
++provided as argument of the log message.
++
++% PING_CHECK_LOAD_ERROR loading Ping Check hooks library failed %1
++This error message indicates an error during loading the Ping Check
++hooks library. The details of the error are provided as argument of
++the log message.
++
++% PING_CHECK_LOAD_OK Ping Check hooks library loaded successfully.
++This info message indicates that the Ping Check hooks library has
++been loaded successfully.
++
++% PING_CHECK_MGR_CHANNEL_DOWN Ping Channel has shutdown, ping checking will be skipped
++This error message is emitted when the underlying ICMP channel
++has stopped due to an unrecoverable error. DHCP service may continue
++to function but without performing ping checks. Prior log messages should
++provide details.
++
++% PING_CHECK_MGR_LEASE_FREE_TO_USE address %1 is free to use for %2
++Logged at debug log level 40.
++This debug message is emitted when ping check has deemed an
++address is free to use. The log arguments detail the lease address
++checked and the query which initiated the check.
++
++% PING_CHECK_MGR_NEXT_ECHO_SCHEDULED for %1, scheduling ECHO_REQUEST %2 of %3
++Logged at debug log level 50.
++This debug message is emitted when the minimum number of ECHO REQUESTs
++is greater than 1 and the next ECHO REQUEST for a given lease address has
++been scheduled.
++
++% PING_CHECK_MGR_RECEIVED_ECHO_REPLY from %1, id %2, sequence %3
++Logged at debug log level 40.
++This debug message is emitted when an ECHO REPLY message has been received.
++The log argument details the source IP address, id, and sequence number of
++the ECHO REPLY.
++
++% PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY from %1, id %2, sequence %3 received after reply-timeout expired
++Logged at debug log level 50.
++This debug message is emitted when an ECHO REPLY has been received after the
++reply-timeout has expired and is no longer of interest. This may be an errant
++ECHO REPLY or it may indicate that the reply-timeout value is too short. The
++log argument details the source IP address, id, and sequence number of the reply.
++
++% PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG for %1, id %2, sequence %3 received after reply-timeout expired
++Logged at debug log level 50.
++This debug message is emitted when an UNREACHABLE message has been received
++after the reply-timeout has expired and is no longer of interest. This may
++be an errant message or it may indicate that the reply-timeout value is
++too short.
++
++% PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG for %1, id %2, sequence %3
++Logged at debug log level 50.
++This debug message is emitted when an UNREACHABLE message has been received.
++The log argument details the target IP address, id, and sequence number from
++the embedded ECHO REQUEST.
++
++% PING_CHECK_MGR_REPLY_RECEIVED_ERROR an error occurred processing an ICMP reply message %1
++This debug message is emitted when an error occurred while processing an inbound
++ICMP message. The log argument describes the specific error.
++
++% PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED for %1, ECHO REQUEST %2 of %3, reply-timeout %4
++Logged at debug log level 50.
++This debug message is emitted when no reply is received to an
++ECHO REQUEST before the configured timeout value, `reply-timeout`
++was reached. The log arguments provides details.
++
++% PING_CHECK_MGR_SEND_COMPLETED_ERROR an error occurred in the send completion callback %1
++This error message is emitted when an unexpected error occurred after the completion of
++a successful write to the PingChannel socket. The log argument describes the
++specific error.
++
++% PING_CHECK_MGR_STARTED ping channel operations are running, number of threads %1
++This message is emitted when the ping check channel has been opened
++and is ready to process requests. The log argument includes the number of
++threads in the channel's thread pool.
++
++% PING_CHECK_MGR_STARTED_SINGLE_THREADED single-threaded ping channel operations are running
++This message is emitted when the ping check channel has been opened
++and is ready to process requests in single-threaded mode.
++
++% PING_CHECK_MGR_START_PING_CHECK for %1, initiated by %2
++Logged at debug log level 40.
++This debug message is emitted when a ping check for an address
++has been initiated. The log arguments detail the lease address to
++ping and the query which initiated the check.
++
++% PING_CHECK_MGR_STOPPED channel operations have stopped
++This message is emitted when the ping check channel operations
++have been stopped.
++
++% PING_CHECK_MGR_STOPPING ping channel operations are stopping
++Logged at debug log level 40.
++This debug message is emitted when the ping check channel is stopping
++operations, typically due to configuration event or server shutdown.
++
++% PING_CHECK_MGR_SUBNET_CONFIG_FAILED user-context for subnet id %1, contains invalid ping-check %2
++This error message indicates that a subnet was updated via subnet commands
++and its 'user-context' contains invalid 'ping-check' configuration. The
++server will log the error once and then use global ping-check parameters
++for the subnet until the configuration is corrected.
++
++% PING_CHECK_PAUSE_FAILED Pausing ping channel operations failed %1
++This error message is emitted when an unexpected error occurred while
++attempting to pause the ping channel's thread pool. This error is highly
++unlikely and indicates a programmatic issue that should be reported as
++defect.
++
++% PING_CHECK_PAUSE_ILLEGAL Pausing ping channel operations not allowed %1
++This error message is emitted when attempting to pause the ping channel's
++thread pool. This indicates that a channel thread attempted to use a critical
++section which would result in a dead-lock. This error is highly unlikely
++and indicates a programmatic issue that should be reported as a defect.
++
++% PING_CHECK_PAUSE_PERMISSIONS_FAILED Permissions check for ping-channel pause failed %1
++This error message is emitted when an unexpected error occurred while
++validating an attempt to pause the ping channel's thread pool. This error
++is highly unlikely and indicates a programmatic issue that should be
++reported as a defect.
++
++% PING_CHECK_RESUME_FAILED Resuming ping channel operations failed %1
++This error message is emitted when an unexpected error occurred while
++attempting to resume operation of the ping channel's thread pool. This
++error is highly unlikely and indicates a programmatic issue that should
++be reported as defect.
++
++% PING_CHECK_UNEXPECTED_READ_ERROR could not start next socket read %1
++This error message occurs when initiating an asynchronous read on the ICMP
++socket failed in an unexpected fashion. The details of the error are provided
++as an argument of the log message.
++
++% PING_CHECK_UNEXPECTED_WRITE_ERROR could not start next socket write %1
++This error message occurs when initiating an asynchronous write on the ICMP
++socket failed in an unexpected fashion. The details of the error are provided
++as an argument of the log message.
++
++% PING_CHECK_UNLOAD Ping Check hooks library has been unloaded
++This info message indicates that the Ping Check hooks library has been
++unloaded.
+diff --git a/src/hooks/dhcp/ping_check/ping_check_mgr.cc b/src/hooks/dhcp/ping_check/ping_check_mgr.cc
+new file mode 100644
+index 0000000000..cb4f2ee1dc
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_mgr.cc
+@@ -0,0 +1,798 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <ping_check_mgr.h>
++#include <ping_check_log.h>
++#include <dhcpsrv/cfgmgr.h>
++#include <hooks/hooks_manager.h>
++#include <util/multi_threading_mgr.h>
++#include <util/chrono_time_utils.h>
++
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::data;
++using namespace isc::hooks;
++using namespace isc::util;
++using namespace std;
++using namespace std::chrono;
++
++namespace ph = std::placeholders;
++
++namespace isc {
++namespace ping_check {
++
++PingCheckMgr::PingCheckMgr()
++ : io_service_(new IOService()), thread_pool_(),
++ store_(new PingContextStore()),
++ channel_(),
++ config_cache_(new ConfigCache()),
++ mutex_(new mutex()),
++ suspended_(false) {
++}
++
++PingCheckMgr::PingCheckMgr(uint32_t num_threads,
++ uint32_t min_echos,
++ uint32_t reply_timeout)
++ : io_service_(new IOService()), thread_pool_(),
++ store_(new PingContextStore()),
++ channel_(),
++ config_cache_(new ConfigCache()),
++ mutex_(new mutex()),
++ suspended_(false) {
++ PingCheckConfigPtr config(new PingCheckConfig());
++ config->setMinPingRequests(min_echos);
++ config->setReplyTimeout(reply_timeout);
++ config->setPingChannelThreads(num_threads);
++ config_cache_->setGlobalConfig(config);
++}
++
++PingCheckMgr::~PingCheckMgr() {
++ stop();
++}
++
++void
++PingCheckMgr::configure(ConstElementPtr params) {
++ if (!params) {
++ isc_throw(dhcp::DhcpConfigError, "params must not be null");
++ return;
++ }
++
++ if (params->getType() != Element::map) {
++ isc_throw(dhcp::DhcpConfigError, "params must be an Element::map");
++ return;
++ }
++
++ PingCheckConfigPtr config(new PingCheckConfig());
++ config->parse(params);
++ config_cache_->setGlobalConfig(config);
++}
++
++void
++PingCheckMgr::updateSubnetConfig(SrvConfigPtr server_config) {
++ // Iterate over subnets and cache configurations for each.
++ ConfigCachePtr local_cache(new ConfigCache());
++ local_cache->setGlobalConfig(config_cache_->getGlobalConfig());
++ auto const& subnets = server_config->getCfgSubnets4()->getAll();
++ for (auto const& subnet : (*subnets)) {
++ auto user_context = subnet->getContext();
++ local_cache->parseAndCacheConfig(subnet->getID(), user_context);
++ }
++
++ // No errors above, replace the existing cache.
++ config_cache_ = local_cache;
++}
++
++const PingCheckConfigPtr
++PingCheckMgr::getGlobalConfig() const {
++ return (config_cache_->getGlobalConfig());
++}
++
++const PingCheckConfigPtr
++PingCheckMgr::getScopedConfig(Lease4Ptr& lease) {
++ if (!lease) {
++ // This really shouldn't happen.
++ isc_throw(InvalidOperation, "PingCheckConfig::getScopedConfig() - lease cannot be empty");
++ }
++
++ auto subnet_id = lease->subnet_id_;
++
++ // If the cache is stale, update it. We do this to catch subnets that have been updated
++ // via subnet_cmds.
++ auto server_config = CfgMgr::instance().getCurrentCfg();
++ auto const& subnet = server_config->getCfgSubnets4()->getBySubnetId(subnet_id);
++ if (!subnet) {
++ // This really shouldn't happen.
++ isc_throw(InvalidOperation, "PingCheckMgr::getScopedConfig() - "
++ "no subnet for id: " << subnet_id
++ << ", for lease address: " << lease->addr_);
++ }
++
++ // If cache is stale flush it and we'll lazy init subnets as we see them.
++ if (subnet->getModificationTime() > config_cache_->getLastFlushTime()) {
++ config_cache_->flush();
++ }
++
++ // If we don't find an entry for this subnet then we haven't seen it
++ // before so parse and cache it. If the subnet doesn't specify ping-check
++ // we cache an empty entry.
++ PingCheckConfigPtr config;
++ if (!config_cache_->findConfig(subnet_id, config)) {
++ auto user_context = subnet->getContext();
++ try {
++ config = config_cache_->parseAndCacheConfig(subnet_id, user_context);
++ } catch (const std::exception& ex) {
++ // We emit and error and then cache an empty entry. This causes us
++ // to log the error once and then default to global settings afterward.
++ // This avoids us relentlessly logging and failing. Remember this
++ // is happening because a subnet was updated with an invalid context via
++ // subnet-cmd.
++ LOG_ERROR(ping_check_logger, PING_CHECK_MGR_SUBNET_CONFIG_FAILED)
++ .arg(subnet_id)
++ .arg(ex.what());
++ config_cache_->cacheConfig(subnet_id, config);
++ }
++ }
++
++ // Return subnet's ping-check config if it specified one, otherwise
++ // return the global config.
++ return (config ? config : config_cache_->getGlobalConfig());
++}
++
++void
++PingCheckMgr::startPing(dhcp::Lease4Ptr& lease, dhcp::Pkt4Ptr& query, hooks::ParkingLotHandlePtr& parking_lot,
++ const PingCheckConfigPtr& config) {
++ if (checkSuspended()) {
++ // Server should not be submitting requests.
++ isc_throw(InvalidOperation, "PingCheckMgr::startPing() - DHCP service is suspended!");
++ }
++
++ if (!channel_ || !channel_->isOpen()) {
++ isc_throw(InvalidOperation, "PingCheckMgr::startPing() - channel isn't open");
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC,
++ PING_CHECK_MGR_START_PING_CHECK)
++ .arg(lease->addr_)
++ .arg(query->getLabel());
++
++ // Adds a context to the store
++ store_->addContext(lease, query, config->getMinPingRequests(),
++ config->getReplyTimeout(), parking_lot);
++
++ // Posts a call to channel's startSend() and startRead(). This will kick-start perpetual
++ // write and read cycles if they are not already running.
++ if (channel_) {
++ channel_->startSend();
++ channel_->startRead();
++ }
++}
++
++void
++PingCheckMgr::startPing(dhcp::Lease4Ptr& lease, dhcp::Pkt4Ptr& query, hooks::ParkingLotHandlePtr& parking_lot) {
++ startPing(lease, query, parking_lot, getGlobalConfig());
++}
++
++bool
++PingCheckMgr::nextToSend(IOAddress& next) {
++ if (checkSuspended()) {
++ return (false);
++ }
++
++ PingContextPtr context = store_->getNextToSend();
++ if (!context) {
++ return (false);
++ }
++
++ next = context->getTarget();
++ // Transition to sending.
++ context->setState(PingContext::SENDING);
++ store_->updateContext(context);
++
++ return (true);
++}
++
++void
++PingCheckMgr::sendCompleted(const ICMPMsgPtr& echo, bool send_failed) {
++ if (checkSuspended()) {
++ return;
++ }
++
++ try {
++ if (!echo) {
++ isc_throw(BadValue, "PingCheckMgr::sendCompleted() - echo is empty");
++ }
++
++ if (echo->getType() != ICMPMsg::ECHO_REQUEST) {
++ isc_throw(BadValue, "PingCheckMgr::sendCompleted() - message type: "
++ << echo->getType() << " is not an ECHO_REQUEST");
++ }
++
++ // Update the context associated with this ECHO_REQUEST.
++ PingContextPtr context = store_->getContextByAddress(echo->getDestination());
++ if (!context) {
++ isc_throw(Unexpected, "PingCheckMgr::sendCompleted() "
++ " no context found for: " << echo->getDestination());
++ }
++
++ if (send_failed) {
++ // Recoverable error occurred which means we can't get to the target's
++ // network (interface down?). Treat this the same as TARGET UNREACHABLE.
++ finishFree(context);
++ } else {
++ // Transition the context to WAITING_FOR_REPLY.
++ context->beginWaitingForReply();
++ store_->updateContext(context);
++ }
++
++ // Update the expiration timer if necessary.
++ setNextExpiration();
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_MGR_SEND_COMPLETED_ERROR)
++ .arg(ex.what());
++ }
++}
++
++void
++PingCheckMgr::replyReceived(const ICMPMsgPtr& reply) {
++ if (checkSuspended()) {
++ return;
++ }
++
++ try {
++ if (!reply) {
++ isc_throw(BadValue, "PingCheckMgr::replyReceived() - echo is empty");
++ }
++
++ switch (reply->getType()) {
++ case ICMPMsg::ECHO_REPLY:
++ handleEchoReply(reply);
++ break;
++ case ICMPMsg::TARGET_UNREACHABLE:
++ // Extract embedded ECHO REQUEST
++ handleTargetUnreachable(reply);
++ break;
++ default:
++ // Ignore anything else.
++ return;
++ }
++
++ setNextExpiration();
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_MGR_REPLY_RECEIVED_ERROR)
++ .arg(ex.what());
++ }
++}
++
++void
++PingCheckMgr::handleEchoReply(const ICMPMsgPtr& echo_reply) {
++ // Update the context associated with this ECHO_REQUEST.
++ PingContextPtr context = store_->getContextByAddress(echo_reply->getSource());
++ if (!context) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_MGR_RECEIVED_UNEXPECTED_ECHO_REPLY)
++ .arg(echo_reply->getSource())
++ .arg(echo_reply->getId())
++ .arg(echo_reply->getSequence());
++ return;
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC,
++ PING_CHECK_MGR_RECEIVED_ECHO_REPLY)
++ .arg(echo_reply->getSource())
++ .arg(echo_reply->getId())
++ .arg(echo_reply->getSequence());
++
++ context->setState(PingContext::TARGET_IN_USE);
++ store_->updateContext(context);
++
++ // If parking is employed, unpark the query from the parking lot,
++ // and set the offer_address_in_use argument in the callout handle
++ // to true, indicating to the server that the lease should be declined
++ // and the DHCPOFFER discarded.
++ auto parking_lot = context->getParkingLot();
++ if (parking_lot) {
++ auto query = context->getQuery();
++ auto callout_handle = query->getCalloutHandle();
++ callout_handle->setArgument("offer_address_in_use", true);
++ parking_lot->unpark(query);
++ }
++
++ // Remove the context from the store.
++ store_->deleteContext(context);
++}
++
++void
++PingCheckMgr::handleTargetUnreachable(const ICMPMsgPtr& unreachable) {
++ // Unpack the embedded ECHO REQUEST.
++ ICMPMsgPtr embedded_echo;
++ auto payload = unreachable->getPayload();
++ embedded_echo = ICMPMsg::unpack(payload.data(), payload.size());
++
++ // Fetch the context associated with the ECHO_REQUEST.
++ PingContextPtr context = store_->getContextByAddress(embedded_echo->getDestination());
++ if (!context) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_MGR_RECEIVED_UNEXPECTED_UNREACHABLE_MSG)
++ .arg(embedded_echo->getDestination())
++ .arg(embedded_echo->getId())
++ .arg(embedded_echo->getSequence());
++ return;
++ }
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_MGR_RECEIVED_UNREACHABLE_MSG)
++ .arg(embedded_echo->getDestination())
++ .arg(embedded_echo->getId())
++ .arg(embedded_echo->getSequence());
++
++ // Render the address usable.
++ finishFree(context);
++}
++
++void
++PingCheckMgr::finishFree(const PingContextPtr& context) {
++ context->setState(PingContext::TARGET_FREE);
++ store_->updateContext(context);
++
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC,
++ PING_CHECK_MGR_LEASE_FREE_TO_USE)
++ .arg(context->getTarget())
++ .arg(context->getQuery()->getLabel());
++
++ // If parking is employed, unpark the query from the parking lot,
++ // and set the offer_address_in_use argument in the callout handle
++ // to false, indicating to the server that the lease is available
++ // and the DHCPOFFER should be sent to the client.
++ auto parking_lot = context->getParkingLot();
++ if (parking_lot) {
++ auto query = context->getQuery();
++ auto callout_handle = query->getCalloutHandle();
++ callout_handle->setArgument("offer_address_in_use", false);
++ parking_lot->unpark(context->getQuery());
++ }
++
++ // Remove the context from the store.
++ store_->deleteContext(context);
++}
++
++void
++PingCheckMgr::channelShutdown() {
++ LOG_ERROR(ping_check_logger, PING_CHECK_MGR_CHANNEL_DOWN);
++ if (io_service_) {
++ // As this is a callback that may be invoked by a channel
++ // thread we post a call to stopService() rather than call
++ // it directly.
++ io_service_->post([&]() { stopService(true); });
++ }
++}
++
++size_t
++PingCheckMgr::processExpiredSince(const TimeStamp& since /* = PingContext::now() */) {
++ auto expired_pings = store_->getExpiredSince(since);
++ size_t more_pings = 0;
++ for (auto const& context : *(expired_pings)) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_MGR_REPLY_TIMEOUT_EXPIRED)
++ .arg(context->getTarget())
++ .arg(context->getEchosSent())
++ .arg(context->getMinEchos())
++ .arg(context->getReplyTimeout());
++
++ if (context->getEchosSent() < context->getMinEchos()) {
++ doNextEcho(context);
++ ++more_pings;
++ } else {
++ finishFree(context);
++ }
++ }
++
++ return (more_pings);
++}
++
++void
++PingCheckMgr::doNextEcho(const PingContextPtr& context) {
++ // Position to do another ping by re-entering WAITING_TO_SEND
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_DETAIL,
++ PING_CHECK_MGR_NEXT_ECHO_SCHEDULED)
++ .arg(context->getTarget())
++ .arg(context->getEchosSent() + 1)
++ .arg(context->getMinEchos());
++
++ context->beginWaitingToSend();
++ store_->updateContext(context);
++}
++
++TimeStamp
++PingCheckMgr::getNextExpiry() {
++ MultiThreadingLock lock(*mutex_);
++ return (next_expiry_);
++}
++
++void
++PingCheckMgr::setNextExpiration() {
++ MultiThreadingLock lock(*mutex_);
++ if (checkSuspendedInternal()) {
++ return;
++ }
++
++ setNextExpirationInternal();
++}
++
++void
++PingCheckMgr::setNextExpirationInternal() {
++ // Find the context that expires soonest.
++ PingContextPtr context = store_->getExpiresNext();
++ if (context) {
++ // if the context's expiry is sooner than current expiry
++ // reschedule expiration timer
++ if ((next_expiry_ == PingContext::EMPTY_TIME()) ||
++ (context->getNextExpiry() < next_expiry_)) {
++ auto now = PingContext::now();
++ auto timeout = duration_cast<milliseconds>(context->getNextExpiry() - now);
++ /// @todo For now we'll impose a 2 ms minimum to avoid thrashing the timer.
++ timeout = (timeout > milliseconds(2) ? timeout : milliseconds(2));
++ next_expiry_ = now + timeout;
++ expiration_timer_->setup(std::bind(&PingCheckMgr::expirationTimedOut,
++ shared_from_this()),
++ timeout.count(), IntervalTimer::ONE_SHOT);
++ }
++ } else {
++ // Nothing waiting to expire. Cancel the timer.
++ cancelExpirationTimerInternal();
++ }
++}
++
++void
++PingCheckMgr::cancelExpirationTimer() {
++ MultiThreadingLock lock(*mutex_);
++ cancelExpirationTimerInternal();
++}
++
++void
++PingCheckMgr::cancelExpirationTimerInternal() {
++ if (expiration_timer_) {
++ expiration_timer_->cancel();
++ next_expiry_ = PingContext::EMPTY_TIME();
++ }
++}
++
++void
++PingCheckMgr::expirationTimedOut() {
++ MultiThreadingLock lock(*mutex_);
++ if (checkSuspendedInternal()) {
++ return;
++ }
++
++ // Process everything that has expired since current time.
++ auto more_pings = processExpiredSince();
++
++ // Update the expiration timer.
++ next_expiry_ = PingContext::EMPTY_TIME();
++ setNextExpirationInternal();
++
++ // In the event there was nothing left to process when timed out,
++ // poke the channel to make sure things are moving.
++ if (more_pings && channel_) {
++ channel_->startSend();
++ channel_->startRead();
++ }
++}
++
++CalloutHandle::CalloutNextStep
++PingCheckMgr::shouldPing(Lease4Ptr& lease, Pkt4Ptr& query,
++ Lease4Ptr& old_lease,
++ const PingCheckConfigPtr& config) {
++
++ // If ping-check is disabled or the channel isn't open,
++ // drop the query from parking and release the offer to the client.
++ if (!config->getEnablePingCheck() || !channel_ || !channel_->isOpen()) {
++ return (CalloutHandle::CalloutNextStep::NEXT_STEP_CONTINUE);
++ }
++
++ // If we're already running check on this address then drop the
++ // query from parking and discard the offer.
++ if (store_->getContextByAddress(lease->addr_)) {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC,
++ PING_CHECK_DUPLICATE_CHECK)
++ .arg(lease->addr_)
++ .arg(query->getLabel());
++ return (CalloutHandle::CalloutNextStep::NEXT_STEP_DROP);
++ }
++
++ // If there's a previous lease that belongs to this client and
++ // it was touched by the client less than ping-cltt-secs ago then
++ // no check is needed. Drop the query from parking and release the
++ // offer to the client,
++ if (old_lease && (old_lease->addr_ == lease->addr_)) {
++ if (old_lease->belongsToClient(lease->hwaddr_, lease->client_id_)) {
++ auto now = time(0);
++ if ((now - old_lease->cltt_) < config->getPingClttSecs()) {
++ return (CalloutHandle::CalloutNextStep::NEXT_STEP_CONTINUE);
++ }
++ }
++ }
++
++ // Leave it parked and do the ping check.
++ return (CalloutHandle::CalloutNextStep::NEXT_STEP_PARK);
++}
++
++void
++PingCheckMgr::startService(NetworkStatePtr network_state) {
++ network_state_ = network_state;
++ io_service_->post([&]() { start(); });
++}
++
++bool
++PingCheckMgr::checkSuspended() {
++ MultiThreadingLock lock(*mutex_);
++ return (checkSuspendedInternal());
++}
++
++bool
++PingCheckMgr::checkSuspendedInternal() {
++ if (!network_state_ || network_state_->isServiceEnabled()) {
++ suspended_ = false;
++ } else {
++ if (!suspended_) {
++ suspended_ = true;
++
++ // Flush the context store, dropping parked queries.
++ flush(false);
++ }
++ }
++
++ return (suspended_);
++}
++
++void
++PingCheckMgr::stopService(bool finish_free) {
++ // Pause the thread pool while we flush the store.
++ pause();
++
++ // Flush the context store. If finish_free is true
++ // the flush will treat the remaining context lease
++ // addresses as free to use and unpark them. This
++ // will cause the server to send out the associated
++ // OFFERs. If it's false we just drop them from
++ // the parking lot.
++ flush(finish_free);
++
++ // Stop the thread pool, destroy the channel and the like.
++ stop();
++}
++
++void
++PingCheckMgr::start() {
++ if (MultiThreadingMgr::instance().isTestMode()) {
++ return;
++ }
++ if (!MultiThreadingMgr::instance().getMode()) {
++ startSingleThreaded();
++ return;
++ }
++
++ // We must be in multi-threading mode.
++ // Add critical section callbacks.
++ MultiThreadingMgr::instance().addCriticalSectionCallbacks("PING_CHECK",
++ std::bind(&PingCheckMgr::checkPermissions, this),
++ std::bind(&PingCheckMgr::pause, this),
++ std::bind(&PingCheckMgr::resume, this));
++
++ // Punt if we're already started.
++ if (thread_pool_ && thread_pool_->isStopped()) {
++ isc_throw(InvalidOperation, "PingCheckMgr already started!");
++ }
++
++ try {
++ auto config = config_cache_->getGlobalConfig();
++ auto use_threads = (config->getPingChannelThreads() ? config->getPingChannelThreads()
++ : MultiThreadingMgr::instance().getThreadPoolSize());
++ thread_pool_.reset(new IoServiceThreadPool(IOServicePtr(), use_threads, true));
++ IOServicePtr pool_ios = thread_pool_->getIOService();
++ channel_ = createChannel(pool_ios);
++ channel_->open();
++ expiration_timer_.reset(new IntervalTimer(pool_ios));
++ thread_pool_->run();
++ LOG_INFO(ping_check_logger, PING_CHECK_MGR_STARTED)
++ .arg(use_threads);
++ } catch (const std::exception& ex) {
++ channel_.reset();
++ thread_pool_.reset();
++ isc_throw(Unexpected, "PingCheckMgr::start failed:" << ex.what());
++ }
++}
++
++void
++PingCheckMgr::startSingleThreaded() {
++ try {
++ auto config = config_cache_->getGlobalConfig();
++ channel_ = createChannel(io_service_);
++ channel_->open();
++ expiration_timer_.reset(new IntervalTimer(io_service_));
++ LOG_INFO(ping_check_logger, PING_CHECK_MGR_STARTED_SINGLE_THREADED);
++ } catch (const std::exception& ex) {
++ channel_.reset();
++ isc_throw(Unexpected, "PingCheckMgr::startSingleThreaded() failed:" << ex.what());
++ }
++}
++
++PingChannelPtr
++PingCheckMgr::createChannel(IOServicePtr io_service) {
++ return (PingChannelPtr(new PingChannel(io_service,
++ std::bind(&PingCheckMgr::nextToSend,
++ this, ph::_1),
++ std::bind(&PingCheckMgr::sendCompleted,
++ this, ph::_1, ph::_2),
++ std::bind(&PingCheckMgr::replyReceived,
++ this, ph::_1),
++ std::bind(&PingCheckMgr::channelShutdown,
++ this))));
++}
++
++void
++PingCheckMgr::checkPermissions() {
++ // Since this function is used as CS callback all exceptions must be
++ // suppressed, unlikely though they may be.
++ try {
++ if (thread_pool_) {
++ thread_pool_->checkPausePermissions();
++ }
++ } catch (const isc::MultiThreadingInvalidOperation& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_PAUSE_ILLEGAL)
++ .arg(ex.what());
++ // The exception needs to be propagated to the caller of the
++ // @ref MultiThreadingCriticalSection constructor.
++ throw;
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_PAUSE_PERMISSIONS_FAILED)
++ .arg(ex.what());
++ }
++}
++
++void
++PingCheckMgr::pause() {
++ if (!MultiThreadingMgr::instance().getMode()) {
++ return;
++ }
++
++ // Since this function is used as CS callback all exceptions must be
++ // suppressed, unlikely though they may be.
++ try {
++ // Cancel the expiration timer.
++ cancelExpirationTimer();
++
++ // Pause the thread pool.
++ if (thread_pool_) {
++ thread_pool_->pause();
++ }
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_PAUSE_FAILED)
++ .arg(ex.what());
++ }
++}
++
++void
++PingCheckMgr::resume() {
++ if (!MultiThreadingMgr::instance().getMode()) {
++ return;
++ }
++
++ // Since this function is used as CS callback all exceptions must be
++ // suppressed, unlikely though they may be.
++ try {
++ if (thread_pool_) {
++ thread_pool_->run();
++ }
++
++ // Restore the expiration timer.
++ setNextExpiration();
++ } catch (const std::exception& ex) {
++ LOG_ERROR(ping_check_logger, PING_CHECK_RESUME_FAILED)
++ .arg(ex.what());
++ }
++}
++
++void
++PingCheckMgr::stop() {
++ LOG_DEBUG(ping_check_logger, isc::log::DBGLVL_TRACE_BASIC, PING_CHECK_MGR_STOPPING);
++
++ // Cancel the expiration timer.
++ cancelExpirationTimer();
++
++ if (channel_) {
++ channel_->close();
++ }
++
++ if (thread_pool_) {
++ // Remove critical section callbacks.
++ MultiThreadingMgr::instance().removeCriticalSectionCallbacks("PING_CHECK");
++
++ // Stop the thread pool.
++ thread_pool_->stop();
++
++ thread_pool_->getIOService()->stopAndPoll();
++
++ // Ditch the thread_pool
++ thread_pool_.reset();
++ }
++ // Ditch the timer. It must be destroyed before the thread pool because in
++ // MT it holds a reference to the pool's IOService.
++ expiration_timer_.reset();
++
++ // Get rid of the channel.
++ channel_.reset();
++
++ if (io_service_) {
++ io_service_->stopAndPoll();
++ }
++
++ LOG_INFO(ping_check_logger, PING_CHECK_MGR_STOPPED);
++}
++
++bool
++PingCheckMgr::isRunning() {
++ // In ST mode, running is an open channel.
++ if (!MultiThreadingMgr::instance().getMode()) {
++ return (channel_ && channel_->isOpen());
++ }
++
++ if (thread_pool_) {
++ return (thread_pool_->isRunning());
++ }
++
++ return (false);
++}
++
++bool
++PingCheckMgr::isStopped() {
++ // In ST mode, stopped equates to no channel.
++ if (!MultiThreadingMgr::instance().getMode()) {
++ return (!channel_);
++ }
++
++ if (thread_pool_) {
++ return (thread_pool_->isStopped());
++ }
++
++ return (true);
++}
++
++bool
++PingCheckMgr::isPaused() {
++ if (thread_pool_) {
++ return (thread_pool_->isPaused());
++ }
++
++ return (false);
++}
++
++void
++PingCheckMgr::flush(bool finish_free /* = false */) {
++ if (!store_) {
++ return;
++ }
++
++ // Fetch them all.
++ auto contexts = store_->getAll();
++ for (auto const& context : *contexts) {
++ if (finish_free) {
++ finishFree(context);
++ } else {
++ auto parking_lot = context->getParkingLot();
++ if (parking_lot) {
++ parking_lot->drop(context->getQuery());
++ }
++ }
++ }
++
++ store_->clear();
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/ping_check_mgr.h b/src/hooks/dhcp/ping_check/ping_check_mgr.h
+new file mode 100644
+index 0000000000..42d11c1b48
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_check_mgr.h
+@@ -0,0 +1,436 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CHECK_MGR_H
++#define PING_CHECK_MGR_H
++
++#include <asiolink/interval_timer.h>
++#include <asiolink/io_address.h>
++#include <asiolink/io_service.h>
++#include <asiolink/io_service_thread_pool.h>
++#include <cc/data.h>
++#include <cc/simple_parser.h>
++#include <dhcpsrv/srv_config.h>
++#include <hooks/callout_handle.h>
++#include <dhcp/pkt4.h>
++#include <dhcpsrv/lease.h>
++#include <dhcpsrv/network_state.h>
++#include <ping_context_store.h>
++#include <ping_channel.h>
++#include <config_cache.h>
++
++#include <boost/enable_shared_from_this.hpp>
++
++#include <mutex>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Defines a pointer to a PingContextStore.
++typedef boost::shared_ptr<PingContextStore> PingContextStorePtr;
++
++/// @brief Ping Check Manager.
++///
++/// PinCheckMgr carries out the higher order management of requests for ping
++/// checks from the server. It is a singleton, instantiated when the library
++/// is loaded. It is responsible for:
++/// 1. Parsing and applying configuration.
++/// 2. Maintaining in-memory store of current ping requests (PingContextStore).
++/// 3. Creating and managing the PingChannel through which individual ICMP ECHO/REPLY
++/// cycles are conducted.
++/// 4. When in multi-threaded mode, it creates an IOServiceThread and synchronizes
++/// its state with Kea core MT.
++class PingCheckMgr : public boost::enable_shared_from_this<PingCheckMgr> {
++public:
++ /// @brief Constructor.
++ explicit PingCheckMgr();
++
++ /// @brief Constructor.
++ ///
++ /// This constructor is used in testing. It permits setting some basic behavior
++ /// parameters directly, rather than requiring calls to @c configure().
++ ///
++ /// @param num_threads number of threads to use in the thread pool (0 means follow
++ /// core thread pool size).
++ /// @param min_echos minimum number of ECHO REQUESTs sent without replies
++ /// received required to declare an address free to offer. Defaults to 1,
++ /// must be greater than zero.
++ /// @param reply_timeout maximum number of milliseconds to wait for an
++ /// ECHO REPLY after an ECHO REQUEST has been sent. Defaults to 100.
++ PingCheckMgr(uint32_t num_threads,
++ uint32_t min_echos = 1,
++ uint32_t reply_timeout = 100);
++
++ /// @brief Destructor.
++ virtual ~PingCheckMgr();
++
++ /// @brief Configure the PingCheckMgr.
++ ///
++ /// @param params map containing the hook library parameters.
++ /// @throw BadValue and similar exceptions on error.
++ void configure(data::ConstElementPtr params);
++
++ /// @brief Update the cache of subnet ping check configurations.
++ ///
++ /// Iterates over the subnets in the given server configuration,
++ /// and caches their ping-check configuration.
++ ///
++ /// @param server_config Server configuration containing the
++ /// configured subnets to process.
++ void updateSubnetConfig(dhcp::SrvConfigPtr server_config);
++
++ /// @brief Creates a ping channel instance.
++ ///
++ /// @param io_service IOService that will drive the channel.
++ ///
++ /// @return pointer to the newly created channel.
++ virtual PingChannelPtr createChannel(asiolink::IOServicePtr io_service);
++
++ /// @brief Initiates a ping check for a given lease and its associated
++ /// DHCPDISCOVER packet.
++ ///
++ /// Adds a context to the store and posts a call to @c PingChannel::startSend().
++ ///
++ /// @param lease lease whose address needs to be ping checked.
++ /// @param query parked DHCPDISCOVER associated with the lease.
++ /// @param parking_lot parking lot in which query is parked. If empty,
++ /// parking is assumed to not be employed.
++ /// @param config configuration parameters to employ.
++ void startPing(dhcp::Lease4Ptr& lease, dhcp::Pkt4Ptr& query,
++ hooks::ParkingLotHandlePtr& parking_lot,
++ const PingCheckConfigPtr& config);
++
++ /// @brief Initiates a ping check for a given lease and its associated
++ /// DHCPDISCOVER packet.
++ ///
++ /// Convenience method used in unit tests which uses global
++ /// configuration parameters only.
++ ///
++ /// @param lease lease whose address needs to be ping checked.
++ /// @param query parked DHCPDISCOVER associated with the lease.
++ /// @param parking_lot parking lot in which query is parked. If empty,
++ /// parking is assumed to not be employed.
++ void startPing(dhcp::Lease4Ptr& lease, dhcp::Pkt4Ptr& query,
++ hooks::ParkingLotHandlePtr& parking_lot);
++
++ /// @brief Callback passed to PingChannel to use to retrieve the next
++ /// address to check.
++ ///
++ /// Fetches the context which has been in the WAITING_TO_SEND state the
++ /// longest and returns its lease address.
++ ///
++ /// @param[out] next upon return it will contain the next target address.
++ /// Contents are only meaningful if the function returns true.
++ ///
++ /// @return True another target address exists, false otherwise.
++ virtual bool nextToSend(asiolink::IOAddress& next);
++
++ /// @brief Callback passed to PingChannel to invoke when an ECHO REQUEST
++ /// send has completed.
++ ///
++ /// If the send completed successfully we'll transition the context to
++ /// WAITING_FOR_REPLY, update the context in the store, and the update
++ /// next expiration.
++ ///
++ /// If the send failed, this implies that a recoverable error occurred, such
++ /// as a interface being down and thus, there is currently no way to send
++ /// the ping to the target network. We'll treat this the same as an ICMP
++ /// TARGET_UNREACHABLE and release the OFFER by calling @c finishFree().
++ ///
++ /// @param echo ICMP echo message that as sent.
++ /// @param send_failed True if the send completed with a non-fatal error,
++ /// false otherwise.
++ virtual void sendCompleted(const ICMPMsgPtr& echo, bool send_failed);
++
++ /// @brief Callback passed to PingChannel to invoke when an ICMP
++ /// reply has been received.
++ ///
++ /// If the reply type is an ECHO REQUEST, it is passed to
++ /// handleEchoRequest(), if it is an UNREACHABLE message it
++ /// is passed to handleTargetUnreachable(), any other message
++ /// type is dropped on the floor and the function returns.
++ /// Upon handler completion, it calls setNextExpiration() to
++ /// update the expiration timer.
++ ///
++ /// @param reply ICMP message that was received.
++ virtual void replyReceived(const ICMPMsgPtr& reply);
++
++ /// @brief Process an ECHO REPLY message.
++ ///
++ /// @param echo_reply ICMP ECHO REPLY message to process.
++ void handleEchoReply(const ICMPMsgPtr& echo_reply);
++
++ /// @brief Process an UNREACHABLE message.
++ ///
++ /// @param unreachable ICMP UNREACHABLE message to process.
++ void handleTargetUnreachable(const ICMPMsgPtr& unreachable);
++
++ /// @brief Processes a context whose address has been deemed free to use.
++ ///
++ /// -# Moves the context to TARGET_FREE state
++ /// -# Updates the context in the store
++ /// -# Unparks the query which will release the DHCPOFFER to the client
++ /// -# Invokes the target free callback (do we still need this?)
++ /// -# Deletes the store from the context
++ ///
++ /// @param context context to process.
++ void finishFree(const PingContextPtr& context);
++
++ /// @brief Position a context to do another ping test.
++ ///
++ /// -# Moves the context to WAITING_SEND_STATE
++ /// -# Updates the context in the store
++ ///
++ /// @param context context to process.
++ void doNextEcho(const PingContextPtr& context);
++
++ /// @brief Callback passed to PingChannel to invoke when it shuts down.
++ ///
++ /// Logs the shutdown and then posts a call to @c stopService() to the
++ /// main IOService.
++ virtual void channelShutdown();
++
++ /// @brief Performs expiration processing for contexts whose WAITING_FOR_REPLY
++ /// states expired prior to a given point in time.
++ ///
++ /// expired_pings = store_->getExpiredSince(since)
++ /// for context : expired_pings {
++ /// unpark context->getQuery()
++ /// store_->deleteContext(context)
++ /// }
++ ///
++ /// @param since point in time to select against. Defaults to current time.
++ /// @return number of contexts scheduled for another ping, zero if none.
++ virtual size_t processExpiredSince(const TimeStamp& since = PingContext::now());
++
++ /// @brief Fetches the time at which expiration timer will next expire.
++ ///
++ /// @return TimeStamp containing the next expiration time.
++ TimeStamp getNextExpiry();
++
++ /// @brief Updates the expiration timer (thread safe).
++ ///
++ /// PingContextPtr next = pings->getExpiresNext()
++ /// if next
++ /// reschedule expiration timer for next->getNextExpiry();
++ /// else
++ /// cancel expiration timer
++ virtual void setNextExpiration();
++
++ /// @brief Updates the expiration timer.
++ ///
++ /// PingContextPtr next = pings->getExpiresNext()
++ /// if next
++ /// reschedule expiration timer for next->getNextExpiry();
++ /// else
++ /// cancel expiration timer
++ virtual void setNextExpirationInternal();
++
++ /// @brief Cancels the expiration timer (thread safe).
++ void cancelExpirationTimer();
++
++ /// @brief Cancels the expiration timer.
++ void cancelExpirationTimerInternal();
++
++ /// @brief Callback passed to expiration timer to invoke on timeout.
++ virtual void expirationTimedOut();
++
++ /// @brief Determines whether or not a lease should be ping checked.
++ ///
++ /// Employs the following logic to determine if a ping-check should
++ /// be conducted:
++ ///
++ /// If there's a previous lease that belongs to this client and
++ /// it was touched by the client less than ping-cltt-secs ago,
++ /// then send the offer to the client without ping checking.
++ ///
++ /// Otherwise a ping-check is called for, leave the query parked.
++ ///
++ /// @param lease prospective lease to check.
++ /// @param query DHCPDISCOVER associated with the lease.
++ /// @param old_lease pre-existing lease for this client (if one).
++ /// @param config configuration parameters to employ.
++ ///
++ /// @return CalloutNextStep indicating what should happen next:
++ /// - status == PARK - ping check it
++ /// - status == CONTINUE - check not needed, release DHCPOFFER to client
++ /// - status == DROP - duplicate check, drop the duplicate DHCPOFFER
++ virtual hooks::CalloutHandle::CalloutNextStep shouldPing(dhcp::Lease4Ptr& lease,
++ dhcp::Pkt4Ptr& query,
++ dhcp::Lease4Ptr& old_lease,
++ const PingCheckConfigPtr& config);
++
++ /// @brief Check if the current thread can perform thread pool state
++ /// transition.
++ ///
++ /// @throw MultiThreadingInvalidOperation if the state transition is done on
++ /// any of the worker threads.
++ void checkPermissions();
++
++ /// @brief Performs a deferred start by posting an invocation of @c start()
++ /// to the given IOService.
++ ///
++ /// @param network_state pointer to server's networks state object.
++ void startService(dhcp::NetworkStatePtr network_state);
++
++ /// @brief Shuts down the manager's channel, flushes the store.
++ ///
++ /// This function gracefully winds down operation:
++ ///
++ /// 1. Pauses the thread pool.
++ /// 2. Flushes the context store, either finishing all contexts as free
++ /// or just dropping them from parking, depending on finish_free parameter.
++ /// 3. Stop the thread pool, shutdown the channel.
++ ///
++ /// @param finish_free if true finishFree() will be invoke on all remaining
++ /// contexts in the store, otherwise their queries are simply dropped from
++ /// the parking lot.
++ void stopService(bool finish_free = false);
++
++ /// @brief Start PingChannel operations.
++ ///
++ /// Will start multi-threaded if core MT is enabled, or calls
++ /// @c startSingleThreaded() if core MT is disabled. Creates
++ /// a thread pool with its own IOService, uses that IOService
++ /// when creating the channel.
++ void start();
++
++ /// @brief Start single-threaded PingChannel operations.
++ ///
++ /// Does not create a thread pool. Uses main thread's IOService
++ /// when creating the channel.
++ void startSingleThreaded();
++
++ /// @brief Pause PingChannel operations.
++ ///
++ /// In multi-threaded mode this pauses the thread pool threads, in
++ /// single-threaded mode it does nothing.
++ void pause();
++
++ /// @brief Resume PingChannel operations.
++ ///
++ /// In multi-threaded mode this resumes the thread pool threads, in
++ /// single-threaded mode it does nothing.
++ void resume();
++
++ /// @brief Flushes the ping context store.
++ ///
++ /// This function iterates over the contexts in the store and then
++ /// either invokes finishFree() or drops their queries from parking
++ /// depending upon finish_free parameter. It assumes the operations
++ /// have ceased (i.e. thread pool is not running).
++ ///
++ /// @param finish_free if true finishFree() will be invoke on all remaining
++ /// contexts in the store, otherwise their queries are simply dropped from
++ /// the parking lot.
++ void flush(bool finish_free = false);
++
++ /// @brief Stop PingChannel operations.
++ void stop();
++
++ /// @brief Indicates if the thread pool is running.
++ ///
++ /// @return True if the thread pool exists and it is in the RUNNING state in
++ /// multi-threaded mode, true if the channel exists and is open in single-threaded
++ /// mode, false otherwise.
++ bool isRunning();
++
++ /// @brief Indicates if the thread pool is stopped.
++ ///
++ /// @return True if the thread pool does not exist or it is in the STOPPED
++ /// state in multi-threaded mode, true if the channel does not exist in
++ /// single-threaded mode, false otherwise.
++ bool isStopped();
++
++ /// @brief Indicates if the thread pool is paused.
++ ///
++ /// @return True if the thread pool exists and it is in the PAUSED state,
++ /// false otherwise. Always returns false in single-threaded mode.
++ bool isPaused();
++
++ /// @brief Checks if operations are currently suspended due to NetworkState.
++ ///
++ /// Thread-safe wrapper around checkSuspendedInternal().
++ ///
++ /// @return True if operations are suspended, false otherwise.
++ bool checkSuspended();
++
++ /// @brief Checks if operations are currently suspended due to NetworkState.
++ ///
++ /// If DHCP service is enabled, operations are not suspended and the function
++ /// returns false. Otherwise operations, if not already suspended, are suspended
++ /// by flushing the PingContext store and the function returns true. The queries
++ /// for flushed contexts are dropped from parking and thus their offers discarded.
++ ///
++ /// @return True if operations are suspended, false otherwise.
++ bool checkSuspendedInternal();
++
++ /// @brief Fetches the current, global configuration parameters.
++ ///
++ /// @return PingCheckConfig reference containing the current configuration.
++ const PingCheckConfigPtr getGlobalConfig() const;
++
++ /// @brief Fetches the current, scoped configuration parameters.
++ ///
++ /// @param lease lease for which the parameters are desired.
++ ///
++ /// @return PingCheckConfig reference containing the current configuration.
++ const PingCheckConfigPtr getScopedConfig(dhcp::Lease4Ptr& lease);
++
++ /// @brief Get the hook I/O service.
++ ///
++ /// @return the hook I/O service.
++ isc::asiolink::IOServicePtr getIOService() {
++ return (io_service_);
++ }
++
++ /// @brief Set the hook I/O service.
++ ///
++ /// @param io_service the hook I/O service.
++ void setIOService(isc::asiolink::IOServicePtr io_service) {
++ io_service_ = io_service;
++ }
++
++protected:
++
++ /// @brief The hook I/O service.
++ isc::asiolink::IOServicePtr io_service_;
++
++ /// @brief Thread pool used when running multi-threaded.
++ asiolink::IoServiceThreadPoolPtr thread_pool_;
++
++ /// @brief In-memory store of PingContexts.
++ PingContextStorePtr store_;
++
++ /// @brief Channel that conducts ICMP messaging.
++ PingChannelPtr channel_;
++
++ /// @brief Warehouses parsed global and subnet configuration.
++ ConfigCachePtr config_cache_;
++
++ /// @brief Tracks whether or not the server is processing DHCP packets.
++ dhcp::NetworkStatePtr network_state_;
++
++ /// @brief TimeStamp of the next expiration event.
++ TimeStamp next_expiry_;
++
++ /// @brief Timer which tracks the next expiration event.
++ asiolink::IntervalTimerPtr expiration_timer_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++
++ /// @brief Indicates whether or not operations have been suspended.
++ bool suspended_;
++};
++
++/// @brief Defines a shared pointer to a PingCheckMgr.
++typedef boost::shared_ptr<PingCheckMgr> PingCheckMgrPtr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/ping_context.cc b/src/hooks/dhcp/ping_check/ping_context.cc
+new file mode 100644
+index 0000000000..45e896f948
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_context.cc
+@@ -0,0 +1,237 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <ping_context.h>
++#include <ping_check_log.h>
++#include <exceptions/exceptions.h>
++#include <util/chrono_time_utils.h>
++#include <iostream>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::hooks;
++using namespace std::chrono;
++
++namespace isc {
++namespace ping_check {
++
++PingContext::PingContext(Lease4Ptr& lease, Pkt4Ptr& query,
++ uint32_t min_echos /* = 1 */,
++ uint32_t reply_timeout /* = 100 */,
++ ParkingLotHandlePtr& parking_lot /* = EMPTY_LOT() */)
++ : min_echos_(min_echos),
++ reply_timeout_(reply_timeout),
++ echos_sent_(0),
++ last_echo_sent_time_(EMPTY_TIME()),
++ send_wait_start_(EMPTY_TIME()),
++ next_expiry_(EMPTY_TIME()),
++ created_time_(PingContext::now()),
++ lease_(lease),
++ query_(query),
++ state_(NEW),
++ parking_lot_(parking_lot) {
++ if (!lease_) {
++ isc_throw(BadValue, "PingContext ctor - lease cannot be empty");
++ }
++
++ if (!query_) {
++ isc_throw(BadValue, "PingContext ctor - query cannot be empty");
++ }
++
++ if (getTarget() == IOAddress::IPV4_ZERO_ADDRESS()) {
++ isc_throw(BadValue, "PingContext ctor - target address cannot be 0.0.0.0");
++ }
++
++ if (min_echos_ == 0) {
++ isc_throw(BadValue, "PingContext ctor - min_echos must be greater than 0");
++ }
++
++ if (reply_timeout_ == 0) {
++ isc_throw(BadValue, "PingContext ctor - reply_timeout must be greater than 0");
++ }
++}
++
++PingContext::State
++PingContext::stringToState(const std::string& state_str) {
++ if (state_str == "NEW") {
++ return (NEW);
++ }
++
++ if (state_str == "WAITING_TO_SEND") {
++ return (WAITING_TO_SEND);
++ }
++
++ if (state_str == "SENDING") {
++ return (SENDING);
++ }
++
++ if (state_str == "WAITING_FOR_REPLY") {
++ return (WAITING_FOR_REPLY);
++ }
++
++ if (state_str == "TARGET_FREE") {
++ return (TARGET_FREE);
++ }
++
++ if (state_str == "TARGET_IN_USE") {
++ return (TARGET_IN_USE);
++ }
++
++ isc_throw(BadValue, "Invalid PingContext::State: '" << state_str << "'");
++}
++
++TimeStamp
++PingContext::now() {
++ return (time_point_cast<milliseconds>(std::chrono::system_clock::now()));
++}
++
++std::string
++PingContext::stateToString(const PingContext::State& state) {
++ std::string label = "";
++ switch (state) {
++ case NEW:
++ label = "NEW";
++ break;
++ case WAITING_TO_SEND:
++ label = "WAITING_TO_SEND";
++ break;
++ case SENDING:
++ label = "SENDING";
++ break;
++ case WAITING_FOR_REPLY:
++ label = "WAITING_FOR_REPLY";
++ break;
++ case TARGET_FREE:
++ label = "TARGET_FREE";
++ break;
++ case TARGET_IN_USE:
++ label = "TARGET_IN_USE";
++ break;
++ }
++
++ return (label);
++}
++
++const IOAddress& PingContext::getTarget() const {
++ return (lease_->addr_);
++}
++
++uint32_t
++PingContext::getMinEchos() const {
++ return (min_echos_);
++}
++
++void
++PingContext::setMinEchos(uint32_t value) {
++ min_echos_ = value;
++}
++
++uint32_t
++PingContext::getReplyTimeout() const {
++ return (reply_timeout_);
++}
++
++void
++PingContext::setReplyTimeout(uint32_t value) {
++ reply_timeout_ = value;
++}
++
++uint32_t
++PingContext::getEchosSent() const {
++ return (echos_sent_);
++}
++
++void
++PingContext::setEchosSent(uint32_t value) {
++ echos_sent_ = value;
++}
++
++const TimeStamp&
++PingContext::getLastEchoSentTime() const {
++ return (last_echo_sent_time_);
++}
++
++void
++PingContext::setLastEchoSentTime(const TimeStamp& value) {
++ last_echo_sent_time_ = value;
++}
++
++const TimeStamp&
++PingContext::getSendWaitStart() const {
++ return (send_wait_start_);
++}
++
++bool
++PingContext::isWaitingToSend() const {
++ return (state_ == WAITING_TO_SEND);
++}
++
++void
++PingContext::setSendWaitStart(const TimeStamp& value) {
++ send_wait_start_ = value;
++}
++
++const TimeStamp&
++PingContext::getNextExpiry() const {
++ return (next_expiry_);
++}
++
++bool
++PingContext::isWaitingForReply() const {
++ return (state_ == WAITING_FOR_REPLY);
++}
++
++void
++PingContext::setNextExpiry(const TimeStamp& value) {
++ next_expiry_ = value;
++}
++
++const TimeStamp&
++PingContext::getCreatedTime() const {
++ return (created_time_);
++}
++
++PingContext::State
++PingContext::getState() const {
++ return (state_);
++}
++
++void
++PingContext::setState(const PingContext::State& value) {
++ state_ = value;
++}
++
++Pkt4Ptr
++PingContext::getQuery() const {
++ return (query_);
++}
++
++Lease4Ptr
++PingContext::getLease() const {
++ return (lease_);
++}
++
++void
++PingContext::beginWaitingToSend(const TimeStamp& begin_time /* = now() */) {
++ state_ = WAITING_TO_SEND;
++ send_wait_start_ = begin_time;
++}
++
++void
++PingContext::beginWaitingForReply(const TimeStamp& begin_time /* = now() */) {
++ ++echos_sent_;
++ last_echo_sent_time_ = begin_time;
++ next_expiry_ = begin_time + milliseconds(reply_timeout_);
++ state_ = WAITING_FOR_REPLY;
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
++
+diff --git a/src/hooks/dhcp/ping_check/ping_context.h b/src/hooks/dhcp/ping_check/ping_context.h
+new file mode 100644
+index 0000000000..2c5b704a04
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_context.h
+@@ -0,0 +1,280 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CONTEXT_H
++#define PING_CONTEXT_H
++
++#include <dhcp/pkt4.h>
++#include <dhcpsrv/lease.h>
++#include <hooks/parking_lots.h>
++
++#include <chrono>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Specifies the type for time stamps.
++using TimeStamp = std::chrono::time_point<std::chrono::system_clock>;
++
++/// @brief Embodies the life cycle of a ping check test for a single address
++/// for a single DHCPDISCOVER.
++///
++/// The class uses a state-model to direct the tasks needed to execute one
++/// or more ECHO REQUEST SEND/WAIT FOR REPLY cycles until the address is
++/// either deemed free to offer or in-use and should not be offered. The
++/// number of cycles conducted is dictated by the minimum number of echos
++/// (@c min_echos_) and whether or not either an ECHO REPLY or DESTINATION
++/// UNREACHABLE are received.
++class PingContext {
++public:
++
++ /// @brief Defines PingContext life cycle states
++ enum State {
++ NEW, // Newly created
++ WAITING_TO_SEND, // Waiting to send next ECHO REQUEST
++ SENDING, // Next ECHO REQUEST is being sent
++ WAITING_FOR_REPLY, // ECHO REQUEST sent, Waiting for reply or timeout
++ TARGET_FREE, // Target has been deemed free to offer.
++ TARGET_IN_USE // Target has been deemed in-use, do not offer
++ };
++
++ /// @brief Converts a string to State
++ ///
++ /// @param state_str Upper case string label to convert
++ /// @return State value corresponding to the given string
++ ///
++ /// @throw BadValue if the string is not a valid state label
++ static State stringToState(const std::string& state_str);
++
++ /// @brief Converts a State to a string
++ ///
++ /// @param state State to convert
++ /// @return string label corresponding to the given state
++ static std::string stateToString(const State& state);
++
++ /// @brief Constructor
++ ///
++ /// @param lease pointer to the lease whose address needs to be checked
++ /// @param query DHCPDISCOVER that instigated the check
++ /// @param min_echos minimum number of ECHO REQUESTs sent without replies
++ /// received required to declare an address free to offer. Defaults to 1,
++ /// must be greater than zero.
++ /// @param reply_timeout maximum number of milliseconds to wait for an
++ /// ECHO REPLY after an ECHO REQUEST has been sent. Defaults to 100,
++ /// must be greater than 0.
++ /// @param parking_lot parking lot in which the query is parked. Defaults
++ /// to an empty pointer.
++ ///
++ /// @throw BadValue if either lease or query are empty, or if the lease
++ /// address is 0.0.0.0
++ PingContext(isc::dhcp::Lease4Ptr& lease, isc::dhcp::Pkt4Ptr& query,
++ uint32_t min_echos = 1, uint32_t reply_timeout = 100,
++ isc::hooks::ParkingLotHandlePtr& parking_lot = EMPTY_LOT());
++
++ /// @brief Destructor
++ virtual ~PingContext() = default;
++
++ /// @brief Fetches the current timestamp (UTC/milliseconds precision)
++ ///
++ /// @return current time as a TimeStamp
++ static TimeStamp now();
++
++ /// @brief Fetches an empty timestamp
++ ///
++ /// @return an empty TimeStamp
++ static const TimeStamp& EMPTY_TIME() {
++ static TimeStamp empty_time;
++ return (empty_time);
++ }
++
++ /// @brief Fetches the minimum timestamp
++ ///
++ /// @return the minimum timestamp
++ static const TimeStamp& MIN_TIME() {
++ static TimeStamp min_time = std::chrono::system_clock::time_point::min();
++ return (min_time);
++ }
++
++ /// @brief Fetches an empty parking lot handle
++ ///
++ /// @return an empty ParkingLotHandlePtr
++ static hooks::ParkingLotHandlePtr& EMPTY_LOT() {
++ static hooks::ParkingLotHandlePtr empty_lot(0);
++ return (empty_lot);
++ }
++
++ /// @brief Fetches the IP address that is under test.
++ ///
++ /// @return IP address as an IOAddress
++ const isc::asiolink::IOAddress& getTarget() const;
++
++ /// @brief Fetches the minimum number of ECHO REQUESTs
++ ///
++ /// @return minimum number of echos as a uint32_t
++ uint32_t getMinEchos() const;
++
++ /// @brief Sets the minimum number of ECHO REQUESTs
++ ///
++ /// @param value new value, must be greater than 0
++ ///
++ /// @throw BadValue if the given value is 0
++ void setMinEchos(uint32_t value);
++
++ /// @brief Fetches the reply timeout (milliseconds)
++ ///
++ /// @return reply timeout as a unit32_t
++ uint32_t getReplyTimeout() const;
++
++ /// @brief Sets the reply timeout
++ ///
++ /// @param value new value in milliseconds, must be greater than 0
++ ///
++ /// @throw BadValue if the given value is 0.
++ void setReplyTimeout(uint32_t value);
++
++ /// @brief Fetches the number of ECHO REQUESTs sent.
++ ///
++ /// @return number of echos sent as a unit32_t
++ uint32_t getEchosSent() const;
++
++ /// @brief Sets the number of ECHO REQUESTs sent.
++ ///
++ /// @param value new value
++ void setEchosSent(uint32_t value);
++
++ /// @brief Fetches the timestamp of when the most recent ECHO REQUEST
++ /// was sent
++ ///
++ /// @return time the last echo was sent as a TimeStamp
++ const TimeStamp& getLastEchoSentTime() const;
++
++ /// @brief Sets the timestamp the most recent ECHO REQUEST was sent
++ ///
++ /// @param value new value
++ void setLastEchoSentTime(const TimeStamp& value);
++
++ /// @brief Fetches the time the context went into WAITING_TO_SEND state
++ ///
++ /// The value returned is only meaningful when the context state is WAITING_TO_SEND.
++ ///
++ /// @return send waits start time as a TimeStamp
++ const TimeStamp& getSendWaitStart() const;
++
++ /// @brief Sets the send wait start timestamp
++ ///
++ /// @param value new value
++ void setSendWaitStart(const TimeStamp& value);
++
++ /// @brief Returns true if state is WAITING_TO_SEND
++ ///
++ /// @return True if the context is in WAITING_TO_SEND state
++ bool isWaitingToSend() const;
++
++ /// @brief Fetches the time at which the WAITING_FOR_REPLY state expires(ed)
++ ///
++ /// The value returned is only meaningful when the context state is WAITING_FOR_REPLY.
++ ///
++ /// @return expiration
++ const TimeStamp& getNextExpiry() const;
++
++ /// @brief Sets the timestamp which specifies the time at which the WAITING_FOR_REPLY state expires
++ /// @param value new value
++ void setNextExpiry(const TimeStamp& value);
++
++ /// @brief Returns true if state is WAITING_FOR_REPLY
++ ///
++ /// @return True if the context is in WAITING_TO_REPLY state
++ bool isWaitingForReply() const;
++
++ /// @brief Fetches the time at which the context was created
++ ///
++ /// @return creation time as a TimeStamp
++ const TimeStamp& getCreatedTime() const;
++
++ /// @brief Fetches the current state.
++ ///
++ /// @return current state as PingContext::State
++ State getState() const;
++
++ /// @brief Sets the state.
++ ///
++ /// @param value new state value
++ void setState(const State& value);
++
++ /// @brief Returns the query that instigated this check
++ ///
++ /// @return query as a Pkt4Ptr
++ isc::dhcp::Pkt4Ptr getQuery() const;
++
++ /// @brief Returns the candidate lease whose address is the target to check
++ ///
++ /// @return lease under test as a Lease4Ptr
++ isc::dhcp::Lease4Ptr getLease() const;
++
++ /// @brief Enters WAITING_TO_SEND state
++ ///
++ /// @param begin_time timestamp of when the state began. Defaults to
++ /// time now. Provided for testing purposes.
++ void beginWaitingToSend(const TimeStamp& begin_time = PingContext::now());
++
++ /// @brief Enters WAITING_TO_REPLY state
++ ///
++ /// @param begin_time timestamp of when the state began. Defaults to
++ /// time now. Provided for testing purposes.
++ void beginWaitingForReply(const TimeStamp& begin_time = PingContext::now());
++
++ /// @brief Fetches the parking lot used for this context.
++ ///
++ /// @return Pointer to the parking lot handle or empty if parking is not
++ /// employed.
++ isc::hooks::ParkingLotHandlePtr getParkingLot() {
++ return (parking_lot_);
++ };
++
++private:
++ /// @brief Minimum number of echos to send without receiving a reply
++ /// before giving up
++ uint32_t min_echos_ = 0;
++
++ /// @brief Amount of time (likely in ms) to wait for an echo reply
++ uint32_t reply_timeout_ = 0;
++
++ /// @brief Number of echos sent since instantiation
++ uint32_t echos_sent_ = 0;
++
++ /// @brief Timestamp the most recent echo send completed
++ TimeStamp last_echo_sent_time_;
++
++ /// @brief Timestamp of entry into waiting_to_send
++ TimeStamp send_wait_start_;
++
++ /// @brief Timestamp the most recent echo times out
++ TimeStamp next_expiry_;
++
++ /// @brief Time context was created
++ TimeStamp created_time_;
++
++ /// @brief Candidate lease to check
++ isc::dhcp::Lease4Ptr lease_;
++
++ /// @brief DHCPDISCOVER packet that instigated this check.
++ isc::dhcp::Pkt4Ptr query_;
++
++ /// @brief Current state of this context
++ State state_;
++
++ /// @brief Parking lot where the associated query is parked.
++ /// If empty parking is not being employed.
++ isc::hooks::ParkingLotHandlePtr parking_lot_;
++};
++
++/// @brief Defines a shared pointer to a PingContext.
++typedef boost::shared_ptr<PingContext> PingContextPtr;
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/ping_context_store.cc b/src/hooks/dhcp/ping_check/ping_context_store.cc
+new file mode 100644
+index 0000000000..35712d5afe
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_context_store.cc
+@@ -0,0 +1,144 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <ping_context_store.h>
++#include <util/multi_threading_mgr.h>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::hooks;
++using namespace isc::util;
++using namespace std::chrono;
++
++namespace isc {
++namespace ping_check {
++
++PingContextPtr
++PingContextStore::addContext(Lease4Ptr& lease, Pkt4Ptr& query,
++ uint32_t min_echos, uint32_t reply_timeout,
++ ParkingLotHandlePtr& parking_lot) {
++
++ MultiThreadingLock lock(*mutex_);
++ PingContextPtr context;
++ try {
++ context.reset(new PingContext(lease, query, min_echos, reply_timeout, parking_lot));
++ } catch (const std::exception& ex) {
++ isc_throw(BadValue, "PingContextStore::addContext failed: " << ex.what());
++ }
++
++ context->beginWaitingToSend();
++ auto ret = pings_.insert(context);
++ if (ret.second == false) {
++ isc_throw(DuplicateContext, "PingContextStore::addContex: context already exists for: "
++ << lease->addr_);
++ }
++
++ return (context);
++}
++
++void
++PingContextStore::updateContext(const PingContextPtr& context) {
++ MultiThreadingLock lock(*mutex_);
++ auto& index = pings_.get<AddressIndexTag>();
++ auto context_iter = index.find(context->getTarget());
++ if (context_iter == index.end()) {
++ isc_throw(InvalidOperation, "PingContextStore::updateContext failed for address: "
++ << context->getTarget() << ", not in store");
++ }
++
++ // Use replace() to re-index contexts.
++ index.replace(context_iter, PingContextPtr(new PingContext(*context)));
++}
++
++void
++PingContextStore::deleteContext(const PingContextPtr& context) {
++ MultiThreadingLock lock(*mutex_);
++ auto& index = pings_.get<AddressIndexTag>();
++ auto context_iter = index.find(context->getTarget());
++ if (context_iter == index.end()) {
++ // Not there, just return.
++ return;
++ }
++
++ // Remove the context from the store.
++ pings_.erase(context_iter);
++}
++
++PingContextPtr
++PingContextStore::getContextByAddress(const IOAddress& address) {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<AddressIndexTag>();
++ auto context_iter = index.find(address);
++ return (context_iter == index.end() ? PingContextPtr()
++ : PingContextPtr(new PingContext(**context_iter)));
++}
++
++PingContextPtr
++PingContextStore::getContextByQuery(Pkt4Ptr& query) {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<QueryIndexTag>();
++ auto context_iter = index.find(query);
++ return (context_iter == index.end() ? PingContextPtr()
++ : PingContextPtr(new PingContext(**context_iter)));
++}
++
++PingContextPtr
++PingContextStore::getNextToSend() {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<NextToSendIndexTag>();
++ auto context_iter = index.lower_bound(boost::make_tuple(true, PingContext::MIN_TIME()));
++ return (context_iter == index.end() ? PingContextPtr()
++ : PingContextPtr(new PingContext(**context_iter)));
++}
++
++PingContextPtr
++PingContextStore::getExpiresNext() {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<ExpirationIndexTag>();
++ auto context_iter = index.lower_bound(boost::make_tuple(true, PingContext::now() + milliseconds(1)));
++ return (context_iter == index.end() ? PingContextPtr()
++ : PingContextPtr(new PingContext(**context_iter)));
++}
++
++PingContextCollectionPtr
++PingContextStore::getExpiredSince(const TimeStamp& since) {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<ExpirationIndexTag>();
++ auto lower_limit = index.lower_bound(boost::make_tuple(true, PingContext::MIN_TIME()));
++ auto upper_limit = index.upper_bound(boost::make_tuple(true, since));
++
++ PingContextCollectionPtr collection(new PingContextCollection());
++ for (auto context_iter = lower_limit; context_iter != upper_limit; ++context_iter) {
++ PingContextPtr context(new PingContext(**context_iter));
++ collection->push_back(context);
++ }
++
++ return (collection);
++}
++
++PingContextCollectionPtr
++PingContextStore::getAll() {
++ MultiThreadingLock lock(*mutex_);
++ auto const& index = pings_.get<AddressIndexTag>();
++ PingContextCollectionPtr collection(new PingContextCollection());
++ for (auto const& context_iter : index) {
++ collection->push_back(PingContextPtr(new PingContext(*context_iter)));
++ }
++
++ return (collection);
++}
++
++void PingContextStore::clear() {
++ MultiThreadingLock lock(*mutex_);
++ pings_.clear();
++}
++
++} // end of namespace ping_check
++} // end of namespace isc
+diff --git a/src/hooks/dhcp/ping_check/ping_context_store.h b/src/hooks/dhcp/ping_check/ping_context_store.h
+new file mode 100644
+index 0000000000..3a7664bfca
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/ping_context_store.h
+@@ -0,0 +1,240 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_CONTEXT_STORE_H
++#define PING_CONTEXT_STORE_H
++
++#include <asiolink/io_address.h>
++#include <ping_context.h>
++
++#include <boost/multi_index/indexed_by.hpp>
++#include <boost/multi_index/member.hpp>
++#include <boost/multi_index/mem_fun.hpp>
++#include <boost/multi_index/ordered_index.hpp>
++#include <boost/multi_index_container.hpp>
++#include <boost/multi_index/composite_key.hpp>
++#include <boost/scoped_ptr.hpp>
++
++#include <mutex>
++#include <vector>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Exception thrown when an attempt was made to add a duplicate context
++class DuplicateContext : public Exception {
++public:
++ DuplicateContext(const char* file, size_t line, const char* what) :
++ isc::Exception(file, line, what) {}
++};
++
++/// @brief Tag for index by target address.
++struct AddressIndexTag { };
++
++/// @brief Tag for index by the query packet.
++struct QueryIndexTag { };
++
++/// @brief Tag for index by send wait start time.
++struct NextToSendIndexTag { };
++
++/// @brief Tag for index by expiration time.
++struct ExpirationIndexTag { };
++
++/// @brief Tag for index by state.
++struct StateIndexTag { };
++
++/// @brief A multi index container holding pointers to PingContexts.
++///
++/// The contexts in the container may be accessed using different indexes:
++/// - using an IPv4 address,
++/// - using a query packet
++/// - using a send wait start time
++/// - using an expiration time
++/// - using a context state
++///
++/// Indexes can be accessed using the index number (from 0 to 2) or a
++/// name tag. It is recommended to use the tags to access indexes as
++/// they do not depend on the order of indexes in the container.
++typedef boost::multi_index_container<
++ // It holds pointers to Lease6 objects.
++ PingContextPtr,
++ boost::multi_index::indexed_by<
++ // Specification of the first index starts here.
++ // This index sorts PingContexts by IPv4 addresses represented as
++ // IOAddress objects.
++ /// @todo Does it need to be ordered or only unique?
++ boost::multi_index::ordered_unique<
++ boost::multi_index::tag<AddressIndexTag>,
++ boost::multi_index::const_mem_fun<PingContext, const isc::asiolink::IOAddress&,
++ &PingContext::getTarget>
++ >,
++
++ // Specification of the second index starts here.
++ // This index sorts contexts by query.
++ boost::multi_index::ordered_unique<
++ boost::multi_index::tag<QueryIndexTag>,
++ boost::multi_index::const_mem_fun<PingContext, isc::dhcp::Pkt4Ptr,
++ &PingContext::getQuery>
++ >,
++
++ // Specification of the third index starts here.
++ // This index sorts contexts by send_wait_start.
++ boost::multi_index::ordered_non_unique<
++ boost::multi_index::tag<NextToSendIndexTag>,
++ boost::multi_index::composite_key<
++ PingContext,
++ // The boolean value specifying if context is waiting to send
++ boost::multi_index::const_mem_fun<PingContext, bool,
++ &PingContext::isWaitingToSend>,
++ // Context expiration time.
++ boost::multi_index::const_mem_fun<PingContext, const TimeStamp&,
++ &PingContext::getSendWaitStart>
++ >
++ >,
++
++ // Specification of the fourth index starts here.
++ // This index sorts contexts by next_expiry.
++ boost::multi_index::ordered_non_unique<
++ boost::multi_index::tag<ExpirationIndexTag>,
++ boost::multi_index::composite_key<
++ PingContext,
++ // The boolean value specifying if context is waiting for a reply
++ boost::multi_index::const_mem_fun<PingContext, bool,
++ &PingContext::isWaitingForReply>,
++ // Context expiration time.
++ boost::multi_index::const_mem_fun<PingContext, const TimeStamp&,
++ &PingContext::getNextExpiry>
++ >
++ >,
++
++ // Specification of the fifth index starts here.
++ // This index sorts contexts by State.
++ boost::multi_index::ordered_non_unique<
++ boost::multi_index::tag<StateIndexTag>,
++ boost::multi_index::const_mem_fun<PingContext, PingContext::State,
++ &PingContext::getState>
++ >
++ >
++> PingContextContainer;
++
++/// @brief Type for a collection of PingContextPtrs.
++typedef std::vector<PingContextPtr> PingContextCollection;
++/// @brief Type for a pointer to a collection of PingContextPtrs.
++typedef boost::shared_ptr<PingContextCollection> PingContextCollectionPtr;
++
++/// @brief Maintains an in-memory store of PingContexts
++///
++/// Provides essential CRUD functions for managing a collection of
++/// PingContexts. Additionally there are finders that can return
++/// contexts by target IP address, instigating query, WAITING_TO_SEND
++/// start time, WAITING_FOR_REPLY expiration time, and context state.
++/// All finders return copies of the contexts found, rather than the
++/// stored context itself.
++class PingContextStore {
++public:
++
++ /// @brief Constructor
++ PingContextStore() : pings_(), mutex_(new std::mutex) {
++ }
++
++ /// @brief Destructor
++ ~PingContextStore() = default;
++
++ /// @brief Creates a new PingContext and adds it to the store
++ ///
++ /// @param lease lease whose address is to be ping checked
++ /// @param query query that instigated the lease
++ /// @param min_echos minimum number of ECHO REQUESTs sent without replies
++ /// received required to declare an address free to offer. Must be
++ /// greater than zero.
++ /// @param reply_timeout maximum number of milliseconds to wait for an
++ /// ECHO REPLY after an ECHO REQUEST has been sent. Must be greater than 0.
++ /// @param parking_lot parking lot in which query is parked. If empty,
++ /// parking is assumed to not be employed.
++ ///
++ /// @return pointer to the newly created context
++ /// @throw DuplicateContext is a context for the lease address already
++ /// exists in the store.
++ PingContextPtr addContext(isc::dhcp::Lease4Ptr& lease,
++ isc::dhcp::Pkt4Ptr& query,
++ uint32_t min_echos,
++ uint32_t reply_timeout,
++ isc::hooks::ParkingLotHandlePtr& parking_lot
++ = PingContext::EMPTY_LOT());
++
++ /// @brief Updates a context in the store.
++ ///
++ /// The context is assumed to already exist in the store.
++ ///
++ /// @param context context to update.
++ ///
++ /// @throw InvalidOperation if PingContext does not exist in the store.
++ void updateContext(const PingContextPtr& context);
++
++ /// @brief Removes the context from the store.
++ ///
++ /// If the context does not exist in the store, it simply returns.
++ ///
++ /// @param context context to delete.
++ void deleteContext(const PingContextPtr& context);
++
++ /// @brief Fetches the context with a given target address
++ ///
++ /// @param address target IP address for which to search
++ ///
++ /// @return pointer to the matching PingContext or an empty pointer if
++ /// not found.
++ PingContextPtr getContextByAddress(const isc::asiolink::IOAddress& address);
++
++ /// @brief Fetches the context with a given query packet
++ ///
++ /// @param query query for which to search
++ ///
++ /// @return pointer to the matching PingContext or an empty pointer if
++ /// not found.
++ PingContextPtr getContextByQuery(isc::dhcp::Pkt4Ptr& query);
++
++ /// @brief Fetches the context in WAITING_TO_SEND with the oldest send wait
++ /// start time.
++ ///
++ /// @return pointer to the matching PingContext or an empty pointer if
++ /// not found.
++ PingContextPtr getNextToSend();
++
++ /// @brief Fetches the context in WAITING_FOR_REPLY with the oldest expiration
++ /// time that has not already passed (i.e. is still in the future)
++ ///
++ /// @return pointer to the matching PingContext or an empty pointer if
++ /// not found.
++ PingContextPtr getExpiresNext();
++
++ /// @brief Fetches the contexts in WAITING_FOR_REPLY that expired since a given time
++ ///
++ /// @param since timestamp to search by. Defaults to current time.
++ ///
++ /// @return a collection of the matching contexts, ordered by expiration time.
++ PingContextCollectionPtr getExpiredSince(const TimeStamp& since = PingContext::now());
++
++ /// @brief Fetches all of the contexts (in order by target)
++ ///
++ /// @return a collection of all contexts in the store.
++ PingContextCollectionPtr getAll();
++
++ /// @brief Removes all contexts from the store.
++ void clear();
++
++private:
++ /// @brief Container instance.
++ PingContextContainer pings_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++};
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/tests/.gitignore b/src/hooks/dhcp/ping_check/tests/.gitignore
+new file mode 100644
+index 0000000000..7e12f9e5be
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/.gitignore
+@@ -0,0 +1 @@
++ping_check_unittests
+diff --git a/src/hooks/dhcp/ping_check/tests/Makefile.am b/src/hooks/dhcp/ping_check/tests/Makefile.am
+new file mode 100644
+index 0000000000..a8c2ea4d92
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/Makefile.am
+@@ -0,0 +1,70 @@
++SUBDIRS = .
++
++AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
++AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/ping_check -I$(top_srcdir)/src/hooks/dhcp/ping_check
++AM_CPPFLAGS += $(BOOST_INCLUDES) $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
++AM_CPPFLAGS += -DPING_CHECK_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/ping_check/.libs/libdhcp_ping_check.so\"
++AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
++
++AM_CXXFLAGS = $(KEA_CXXFLAGS)
++
++if USE_STATIC_LINK
++AM_LDFLAGS = -static
++endif
++
++# Unit test data files need to get installed.
++EXTRA_DIST =
++
++CLEANFILES = *.gcno *.gcda
++
++TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
++
++LOG_COMPILER = $(LIBTOOL)
++AM_LOG_FLAGS = --mode=execute
++
++TESTS =
++if HAVE_GTEST
++TESTS += ping_check_unittests
++
++ping_check_unittests_SOURCES = run_unittests.cc
++ping_check_unittests_SOURCES += icmp_endpoint_unittests.cc
++ping_check_unittests_SOURCES += icmp_socket_unittests.cc
++ping_check_unittests_SOURCES += ping_context_unittests.cc
++ping_check_unittests_SOURCES += ping_context_store_unittests.cc
++ping_check_unittests_SOURCES += icmp_msg_unittests.cc
++ping_check_unittests_SOURCES += ping_test_utils.h
++ping_check_unittests_SOURCES += ping_channel_unittests.cc
++ping_check_unittests_SOURCES += ping_check_mgr_unittests.cc
++ping_check_unittests_SOURCES += ping_check_config_unittests.cc
++ping_check_unittests_SOURCES += config_cache_unittests.cc
++
++ping_check_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
++
++ping_check_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
++
++ping_check_unittests_CXXFLAGS = $(AM_CXXFLAGS)
++
++ping_check_unittests_LDADD = $(top_builddir)/src/hooks/dhcp/ping_check/libping_check.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
++ping_check_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
++ping_check_unittests_LDADD += $(LOG4CPLUS_LIBS)
++ping_check_unittests_LDADD += $(CRYPTO_LIBS)
++ping_check_unittests_LDADD += $(BOOST_LIBS)
++ping_check_unittests_LDADD += $(GTEST_LDADD)
++endif
++noinst_PROGRAMS = $(TESTS)
+diff --git a/src/hooks/dhcp/ping_check/tests/config_cache_unittests.cc b/src/hooks/dhcp/ping_check/tests/config_cache_unittests.cc
+new file mode 100644
+index 0000000000..f4e48d6591
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/config_cache_unittests.cc
+@@ -0,0 +1,245 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which verify the subnet ping-check
++/// configuration cache.
++
++#include <config.h>
++#include <config_cache.h>
++#include <dhcpsrv/cfgmgr.h>
++#include <hooks/callout_manager.h>
++#include <hooks/hooks.h>
++#include <testutils/gtest_utils.h>
++#include <testutils/multi_threading_utils.h>
++
++#include <boost/date_time/posix_time/posix_time.hpp>
++#include <gtest/gtest.h>
++#include <sstream>
++
++using namespace std;
++using namespace isc;
++using namespace isc::data;
++using namespace isc::dhcp;
++using namespace isc::hooks;
++using namespace isc::ping_check;
++using namespace isc::test;
++using namespace boost::posix_time;
++
++namespace {
++
++/// @brief ConfigCache derivation that allows flush time to be modified.
++class TestConfigCache : public ConfigCache {
++public:
++ /// @brief Constructor
++ TestConfigCache() {
++ }
++
++ /// @brief Destructor
++ virtual ~TestConfigCache() {
++ }
++
++ /// @brief Adjusts the last flush time by the given amount.
++ ///
++ /// @param offset signed value in seconds to add to cache's last
++ /// flush time value
++ void tweakLastFlushTime(int offset) {
++ setModificationTime(getLastFlushTime() + seconds(offset));
++ }
++};
++
++/// @brief Test fixture for testing ConfigCache.
++class ConfigCacheTest : public ::testing::Test {
++public:
++ /// @brief Constructor
++ ConfigCacheTest() {
++ isc::util::MultiThreadingMgr::instance().setMode(false);
++ }
++
++ /// @brief Destructor
++ virtual ~ConfigCacheTest() {
++ }
++
++ /// @brief Verifies construction of a ConfigCache.
++ void testConstruction() {
++ // We use a BaseStampedElement to get the current time to ensure we
++ // are using the same time perspective (currently local) as StampedElements do.
++ BaseStampedElement now;
++ ptime start_time = now.getModificationTime();
++
++ // Create a new cache.
++ TestConfigCache configs;
++ EXPECT_EQ(configs.size(), 0);
++
++ // Verify that last_flush_time_ has been set and that the
++ // cache has no entries.
++ ptime last_flush_time = configs.getLastFlushTime();
++ EXPECT_GE(last_flush_time, start_time);
++
++ // Verify that looking for an entry in an empty cache
++ // gracefully finds nothing.
++ PingCheckConfigPtr fetched_config;
++ EXPECT_FALSE(configs.findConfig(999, fetched_config));
++ EXPECT_FALSE(fetched_config);
++ }
++
++ /// @brief Verifies that invalid user-context config is rejected gracefully.
++ void testInvalidConfig() {
++ // Create a new cache.
++ TestConfigCache configs;
++ EXPECT_EQ(configs.size(), 0);
++
++ // An invalid keyword should fail.
++ std::string json =
++ R"({
++ "ping-check" : {
++ "bogus" : 777
++ }
++ })";
++
++ ConstElementPtr user_context;
++ ASSERT_NO_THROW_LOG(user_context = Element::fromJSON(json));
++
++ ASSERT_THROW_MSG(configs.parseAndCacheConfig(1, user_context), DhcpConfigError,
++ "spurious 'bogus' parameter");
++
++ EXPECT_EQ(configs.size(), 0);
++ }
++
++ /// @brief Verifies that valid user-context supplied config are cached correctly.
++ void testValidConfig() {
++ // Create a new cache.
++ TestConfigCache configs;
++ EXPECT_EQ(configs.size(), 0);
++
++ // A valid config should get cached.
++ std::string json =
++ R"({
++ "ping-check" : {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 2,
++ "reply-timeout" : 375,
++ "ping-cltt-secs" : 120,
++ "ping-channel-threads" : 6
++ }
++ })";
++
++ ConstElementPtr user_context;
++ ASSERT_NO_THROW_LOG(user_context = Element::fromJSON(json));
++
++ // Verify that we cache a valid config.
++ PingCheckConfigPtr config;
++ ASSERT_NO_THROW_LOG(config = configs.parseAndCacheConfig(1, user_context));
++ ASSERT_TRUE(config);
++ EXPECT_EQ(configs.size(), 1);
++
++ // Verify we can retrieve the cached config.
++ PingCheckConfigPtr fetched_config;
++ ASSERT_TRUE(configs.findConfig(1, fetched_config));
++ EXPECT_EQ(fetched_config, config);
++ }
++
++ /// @brief Verifies that an empty config pointer can be cached.
++ void testConfigCacheEmptyConfig() {
++ // Create a new cache.
++ TestConfigCache configs;
++ EXPECT_EQ(configs.size(), 0);
++
++ // Verify that we can cache an empty config pointer.
++ PingCheckConfigPtr no_config;
++ ASSERT_NO_THROW_LOG(configs.cacheConfig(1, no_config));
++ EXPECT_EQ(configs.size(), 1);
++
++ // Verify we can retrieve the cached empty config pointer.
++ PingCheckConfigPtr fetched_config;
++ ASSERT_TRUE(configs.findConfig(1, fetched_config));
++ ASSERT_FALSE(fetched_config);
++ }
++
++ /// @brief Verifies that the cache can be cleared correctly.
++ void testFlushCache() {
++ // Create a new cache.
++ TestConfigCache configs;
++ EXPECT_EQ(configs.size(), 0);
++
++ ptime last_flush_time = configs.getLastFlushTime();
++
++ // Now let's wind the clock back on last_flush_time.
++ configs.tweakLastFlushTime(-1000);
++ EXPECT_LT(configs.getLastFlushTime(), last_flush_time);
++ last_flush_time = configs.getLastFlushTime();
++
++ // Make a simple valid config.
++ std::string json =
++ R"({
++ "ping-check": {
++ "enable-ping-check" : true
++ }
++ })";
++
++ ConstElementPtr user_context;
++ ASSERT_NO_THROW_LOG(user_context = Element::fromJSON(json));
++
++ for (int id = 1; id < 5; ++id) {
++ PingCheckConfigPtr config;
++ ASSERT_NO_THROW_LOG(config = configs.parseAndCacheConfig(id, user_context));
++ ASSERT_TRUE(config);
++ EXPECT_EQ(configs.size(), id);
++ }
++
++ // Verify we can explicitly clear the cache. Should be no entries
++ // and last_flush_time should be updated.
++ configs.flush();
++ EXPECT_GT(configs.getLastFlushTime(), last_flush_time);
++ EXPECT_EQ(configs.size(), 0);
++ }
++};
++
++TEST_F(ConfigCacheTest, construction) {
++ testConstruction();
++}
++
++TEST_F(ConfigCacheTest, constructionMultiThreading) {
++ MultiThreadingTest mt;
++ testConstruction();
++}
++
++TEST_F(ConfigCacheTest, invalidConfig) {
++ testInvalidConfig();
++}
++
++TEST_F(ConfigCacheTest, invalidConfigMultiThreading) {
++ MultiThreadingTest mt;
++ testInvalidConfig();
++}
++
++TEST_F(ConfigCacheTest, validConfig) {
++ testValidConfig();
++}
++
++TEST_F(ConfigCacheTest, validConfigMultiThreading) {
++ MultiThreadingTest mt;
++ testValidConfig();
++}
++
++TEST_F(ConfigCacheTest, configCacheEmptyConfig) {
++ testConfigCacheEmptyConfig();
++}
++
++TEST_F(ConfigCacheTest, configCacheEmptyConfigMultiThreading) {
++ MultiThreadingTest mt;
++ testConfigCacheEmptyConfig();
++}
++
++TEST_F(ConfigCacheTest, flushCache) {
++ testFlushCache();
++}
++
++TEST_F(ConfigCacheTest, flushCacheMultiThreading) {
++ MultiThreadingTest mt;
++ testFlushCache();
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/icmp_endpoint_unittests.cc b/src/hooks/dhcp/ping_check/tests/icmp_endpoint_unittests.cc
+new file mode 100644
+index 0000000000..e9ed8dcb9b
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/icmp_endpoint_unittests.cc
+@@ -0,0 +1,44 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++#include <asiolink/asio_wrapper.h>
++#include <asiolink/io_address.h>
++#include <icmp_endpoint.h>
++
++#include <gtest/gtest.h>
++
++#include <string>
++
++using namespace isc::asiolink;
++using namespace isc::ping_check;
++using namespace std;
++
++// This test checks that the endpoint can manage its own internal
++// boost::asio::ip::icmp::endpoint object for IPv4.
++TEST(ICMPEndpointTest, v4Address) {
++ const string test_address("192.0.2.1");
++
++ IOAddress address(test_address);
++ ICMPEndpoint endpoint(address);
++
++ EXPECT_TRUE(address == endpoint.getAddress());
++ EXPECT_EQ(static_cast<short>(IPPROTO_ICMP), endpoint.getProtocol());
++ EXPECT_EQ(AF_INET, endpoint.getFamily());
++}
++
++// This test checks that the endpoint can manage its own internal
++// boost::asio::ip::icmp::endpoint object for IPv6.
++TEST(ICMPEndpointTest, v6Address) {
++ const string test_address("2001:db8::1235");
++
++ IOAddress address(test_address);
++ ICMPEndpoint endpoint(address);
++
++ EXPECT_TRUE(address == endpoint.getAddress());
++ EXPECT_EQ(static_cast<short>(IPPROTO_ICMPV6), endpoint.getProtocol());
++ EXPECT_EQ(AF_INET6, endpoint.getFamily());
++}
+diff --git a/src/hooks/dhcp/ping_check/tests/icmp_msg_unittests.cc b/src/hooks/dhcp/ping_check/tests/icmp_msg_unittests.cc
+new file mode 100644
+index 0000000000..36c7056840
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/icmp_msg_unittests.cc
+@@ -0,0 +1,172 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the ICMPMsg class.
++
++#include <config.h>
++#include <icmp_msg.h>
++#include <asiolink/io_address.h>
++#include <testutils/gtest_utils.h>
++#include <util/str.h>
++
++#include <gtest/gtest.h>
++#include <list>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::ping_check;
++
++namespace {
++
++// Verifies accessors.
++TEST(ICMPMsgTest, basics) {
++ ICMPMsgPtr msg(new ICMPMsg());
++
++ msg->setType(ICMPMsg::ECHO_REPLY);
++ EXPECT_EQ(ICMPMsg::ECHO_REPLY, msg->getType());
++
++ msg->setCode(77);
++ EXPECT_EQ(77, msg->getCode());
++
++ msg->setChecksum(0x8899);
++ EXPECT_EQ(0x8899, msg->getChecksum());
++
++ msg->setId(0x1122);
++ EXPECT_EQ(0x1122, msg->getId());
++
++ msg->setSequence(0x3344);
++ EXPECT_EQ(0x3344, msg->getSequence());
++
++ msg->setSource(IOAddress("192.0.2.1"));
++ EXPECT_EQ(IOAddress("192.0.2.1"), msg->getSource());
++
++ msg->setDestination(IOAddress("192.0.2.2"));
++ EXPECT_EQ(IOAddress("192.0.2.2"), msg->getDestination());
++
++ std::vector<uint8_t> payload{ 0x55, 0x66, 0x77, 0x88, 0x99 };
++ msg->setPayload(payload.data(), payload.size());
++ EXPECT_EQ(payload, msg->getPayload());
++}
++
++// Verifies that a valid ECHO REPLY message can be unpacked.
++TEST(ICMPMsgTest, unpackValidEchoReply) {
++ // Create wire data for a valid ECHO REPLY.
++ std::string echo_reply =
++ "45:00:00:30:73:8a:00:00:40:01:a0:ff:b2:10:01:19:b2:10:01:0a:"
++ "00:00:33:11:55:66:77:88:"
++ "00:00:00:00:00:00:00:00:"
++ "00:00:00:00:00:00:00:00:"
++ "00:00:00:00";
++
++ std::vector<uint8_t> wire_data;
++ ASSERT_NO_THROW_LOG(util::str::decodeSeparatedHexString(echo_reply, ":", wire_data));
++
++ // Unpack the wire data.
++ ICMPMsgPtr msg;
++ ASSERT_NO_THROW_LOG(msg = ICMPMsg::unpack(wire_data.data(), wire_data.size()));
++ ASSERT_TRUE(msg);
++
++ // Verify the reply contents.
++ EXPECT_EQ(ICMPMsg::ECHO_REPLY, msg->getType());
++ EXPECT_EQ(0, msg->getCode());
++ EXPECT_EQ(0x3311, msg->getChecksum());
++ EXPECT_EQ(0x5566, msg->getId());
++ EXPECT_EQ(0x7788, msg->getSequence());
++ EXPECT_EQ(IOAddress("178.16.1.25"), msg->getSource());
++ EXPECT_EQ(IOAddress("178.16.1.10"), msg->getDestination());
++
++ std::vector<uint8_t> payload{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
++ EXPECT_EQ(payload, msg->getPayload());
++}
++
++// Verifies that a valid DESTINATION UNREACHABLE message can be unpacked.
++TEST(ICMPMsgTest, unpackValidUnreachable) {
++ // Valid destination unreachable message. Payload is the original
++ // ECHO request.
++ std::string unreachable =
++ "45:c0:00:4c:31:b3:00:00:40:01:e2:09:b2:10:01:0a:b2:10:01:0a:"
++ "03:01:fc:fe:00:00:00:00:"
++ "45:00:00:30:e3:e2:40:00:40:01:f0:5c:"
++ "b2:10:01:0a:b2:10:01:63:08:00:2b:11:"
++ "55:66:77:88:00:00:00:00:00:00:00:00:"
++ "00:00:00:00:00:00:00:00:00:00:00:00";
++
++ // Create the wire data.
++ std::vector<uint8_t> wire_data;
++ ASSERT_NO_THROW_LOG(util::str::decodeSeparatedHexString(unreachable, ":", wire_data));
++
++ // Unpack the outer message.
++ ICMPMsgPtr msg;
++ ASSERT_NO_THROW_LOG(msg = ICMPMsg::unpack(wire_data.data(), wire_data.size()));
++ ASSERT_TRUE(msg);
++
++ // Verify its contents.
++ EXPECT_EQ(ICMPMsg::TARGET_UNREACHABLE, msg->getType());
++ EXPECT_EQ(1, msg->getCode());
++ EXPECT_EQ(0xfcfe, msg->getChecksum());
++ EXPECT_EQ(0, msg->getId());
++ EXPECT_EQ(0, msg->getSequence());
++ EXPECT_EQ(IOAddress("178.16.1.10"), msg->getSource());
++ EXPECT_EQ(IOAddress("178.16.1.10"), msg->getDestination());
++
++ // Now unpack the original ECHO from the outer message payload.
++ std::vector<uint8_t> payload(wire_data.begin() + 28, wire_data.end());
++ EXPECT_EQ(payload, msg->getPayload());
++
++ ICMPMsgPtr payload_msg;
++ ASSERT_NO_THROW_LOG(payload_msg = ICMPMsg::unpack(payload.data(), payload.size()));
++ ASSERT_TRUE(payload_msg);
++
++ // Verify the original ECHO contents.
++ EXPECT_EQ(ICMPMsg::ECHO_REQUEST, payload_msg->getType());
++ EXPECT_EQ(0, payload_msg->getCode());
++ EXPECT_EQ(0x2b11, payload_msg->getChecksum());
++ EXPECT_EQ(0x5566, payload_msg->getId());
++ EXPECT_EQ(0x7788, payload_msg->getSequence());
++ EXPECT_EQ(IOAddress("178.16.1.10"), payload_msg->getSource());
++ EXPECT_EQ(IOAddress("178.16.1.99"), payload_msg->getDestination());
++}
++
++// Verifies the malformed packets are detected.
++TEST(ICMPMsgTest, unpackInValidPackets) {
++ // Contains a test scenario.
++ struct Scenario {
++ // Wire data to submit to unpack.
++ std::string wire_data_;
++ // Expected exception message.
++ std::string error_msg_;
++ };
++
++ // List of scenarios to test.
++ std::list<Scenario> scenarios = {
++ {
++ // Truncated IP header
++ "45:c0:00:4c:31:b3:00:00:40:01:e2:09:b2",
++ "ICMPMsg::unpack - truncated ip header, length: 13"
++ },
++ {
++ // Truncated packet
++ "45:c0:00:4c:31:b3:00:00:40:01:e2:09:b2:10:01:0a:b2:10:01:0a:"
++ "03:01:fc:fe:00:00:00:00:"
++ "45:00:00:30:e3:e2:40:00:40:01:f0:5c",
++ "ICMPMsg::truncated packet? length: 40, hlen: 20"
++ }
++
++ };
++
++ // Iterate over scenarios.
++ for (auto const& scenario : scenarios) {
++ // Create the wire data.
++ std::vector<uint8_t> wire_data;
++ ASSERT_NO_THROW_LOG(util::str::decodeSeparatedHexString(scenario.wire_data_, ":", wire_data));
++ ASSERT_THROW_MSG(ICMPMsg::unpack(wire_data.data(), wire_data.size()), BadValue, scenario.error_msg_);
++ }
++}
++
++/// @todo YOU NEED some round trip tests that test packing!
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/icmp_socket_unittests.cc b/src/hooks/dhcp/ping_check/tests/icmp_socket_unittests.cc
+new file mode 100644
+index 0000000000..2394b360ca
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/icmp_socket_unittests.cc
+@@ -0,0 +1,380 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// \brief Test of ICMPSocket
++///
++/// Tests the functionality of a ICMPSocket by working through an open-send-
++/// receive-close sequence and checking that the asynchronous notifications
++/// work.
++
++#include <config.h>
++#include <asiolink/asio_wrapper.h>
++#include <asiolink/interval_timer.h>
++#include <asiolink/io_address.h>
++#include <asiolink/io_service.h>
++#include <icmp_socket.h>
++#include <icmp_msg.h>
++#include <exceptions/exceptions.h>
++#include <util/buffer.h>
++#include <testutils/gtest_utils.h>
++
++#include <boost/shared_ptr.hpp>
++#include <boost/enable_shared_from_this.hpp>
++#include <boost/date_time/posix_time/posix_time.hpp>
++#include <gtest/gtest.h>
++
++#include <string>
++#include <arpa/inet.h>
++#include <netinet/in.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <algorithm>
++#include <cstdlib>
++#include <cstddef>
++#include <list>
++#include <vector>
++#include <unistd.h>
++
++#include <netinet/ip.h>
++#include <netinet/ip_icmp.h>
++
++using namespace isc;
++using namespace boost::asio;
++using namespace boost::posix_time;
++using namespace isc::asiolink;
++using namespace isc::ping_check;
++using namespace isc::util;
++using namespace std;
++
++namespace ph = std::placeholders;
++
++namespace {
++
++/// @brief Test timeout (ms).
++const long TEST_TIMEOUT = 10000;
++
++/// @brief Type of the function implementing a callback invoked by the
++/// @c SocketCallback functor.
++typedef std::function<void(boost::system::error_code ec, size_t length)>
++ SocketCallbackFunction;
++
++/// @brief Callback class for socket IO operations
++///
++/// An instance of this object is passed to the asynchronous I/O functions
++/// and the operator() method is called when when an asynchronous I/O
++/// completes. The arguments to the completion callback are stored for later
++/// retrieval.
++class SocketCallback {
++public:
++
++ /// @brief Structure that houses callback invocation data.
++ struct PrivateData {
++ PrivateData() :
++ error_code_(), length_(0), called_(false), name_("")
++ {}
++
++ boost::system::error_code error_code_; ///< Completion error code
++ size_t length_; ///< Number of bytes transferred
++ bool called_; ///< Set true when callback called
++ std::string name_; ///< Which of the objects this is
++ };
++
++ /// @brief Constructor
++ ///
++ /// Constructs the object. It also creates the data member pointed to by
++ /// a shared pointer. When used as a callback object, this is copied as it
++ /// is passed into the asynchronous function. This means that there are two
++ /// objects and inspecting the one we passed in does not tell us anything.
++ ///
++ /// Therefore we use a boost::shared_ptr. When the object is copied, the
++ /// shared pointer is copied, which leaves both objects pointing to the same
++ /// data.
++ ///
++ /// @param which Which of the two callback objects this is
++ explicit SocketCallback(const std::string& which) : data_(new PrivateData())
++ {
++ setName(which);
++ }
++
++ /// @brief Destructor
++ ///
++ /// No code needed, destroying the shared pointer destroys the private data.
++ virtual ~SocketCallback()
++ {}
++
++ /// @brief Clears the current values of invocation data members.
++ void clear() {
++ setCode(0);
++ setLength(0);
++ setCalled(false);
++ }
++
++ /// @brief Callback Function
++ ///
++ /// Called when an asynchronous I/O completes, this stores the
++ /// completion error code and the number of bytes transferred.
++ ///
++ /// @param ec I/O completion error code passed to callback function.
++ /// @param length Number of bytes transferred
++ virtual void operator()(boost::system::error_code ec, size_t length = 0) {
++ data_->error_code_ = ec;
++ setLength(length);
++ setCalled(true);
++ }
++
++ /// @brief Get I/O completion error code
++ int getCode() {
++ return (data_->error_code_.value());
++ }
++
++ /// @brief Set I/O completion code
++ ///
++ /// @param code New value of completion code
++ void setCode(int code) {
++ data_->error_code_ = boost::system::error_code(code, boost::system::error_code().category());
++ }
++
++ /// @brief Get number of bytes transferred in I/O
++ size_t getLength() const {
++ return (data_->length_);
++ }
++
++ /// @brief Set number of bytes transferred in I/O
++ ///
++ /// @param length New value of length parameter
++ void setLength(size_t length) {
++ data_->length_ = length;
++ }
++
++ /// @brief Get flag to say when callback was called
++ bool getCalled() const {
++ return (data_->called_);
++ }
++
++ /// @brief Set flag to say when callback was called
++ ///
++ /// @param called New value of called parameter
++ void setCalled(bool called) {
++ data_->called_ = called;
++ }
++
++ /// @brief Return instance of callback name
++ std::string getName() const {
++ return (data_->name_);
++ }
++
++ /// @brief Set callback name
++ ///
++ /// @param name New value of the callback name
++ void setName(const std::string& name) {
++ data_->name_ = name;
++ }
++
++private:
++ boost::shared_ptr<PrivateData> data_; ///< Pointer to private data
++};
++
++/// @brief Socket and pointer types for sending and receiving ICMP echos.
++typedef ICMPSocket<SocketCallback> PingSocket;
++typedef boost::shared_ptr<PingSocket> PingSocketPtr;
++
++/// @brief Simple test fixture for testing ICMPSocket.
++class ICMPSocketTest : public ::testing::Test {
++public:
++ /// @brief Constructor.
++ ICMPSocketTest()
++ : io_service_(new IOService()), test_timer_(io_service_) {
++ test_timer_.setup(std::bind(&ICMPSocketTest::timeoutHandler, this, true),
++ TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
++ }
++
++ /// @brief Destructor.
++ virtual ~ICMPSocketTest() {
++ test_timer_.cancel();
++ io_service_->stopAndPoll();
++ }
++
++ /// @brief Indicates if current user is not root
++ ///
++ /// @return True if neither the uid or the effective
++ /// uid is root.
++ static bool notRoot() {
++ return (getuid() != 0 && geteuid() != 0);
++ }
++
++ /// @brief Callback function invoke upon test timeout.
++ ///
++ /// It stops the IO service and reports test timeout.
++ ///
++ /// @param fail_on_timeout Specifies if test failure should be reported.
++ void timeoutHandler(const bool fail_on_timeout) {
++ if (fail_on_timeout) {
++ ADD_FAILURE() << "Timeout occurred while running the test!";
++ }
++ io_service_->stop();
++ }
++
++ /// @brief IOService instance used by thread pools.
++ IOServicePtr io_service_;
++
++ /// @brief Asynchronous timer service to detect timeouts.
++ IntervalTimer test_timer_;
++
++ /// @brief Returns pointer to the first byte of the input buffer.
++ ///
++ /// @throw InvalidOperation if called when the buffer is empty.
++ uint8_t* getInputBufData() {
++ if (input_buf_.empty()) {
++ isc_throw(InvalidOperation, "TcpConnection::getInputBufData() - cannot access empty buffer");
++ }
++
++ return (input_buf_.data());
++ }
++
++ /// @brief Returns input buffer size.
++ size_t getInputBufSize() const {
++ return (input_buf_.size());
++ }
++
++ /// @brief Set the capacity of the input buffer
++ ///
++ /// @param buf_size maximum number of bytes allowed in the buffer
++ void resizeInputBuf(size_t buf_size) {
++ input_buf_.resize(buf_size);
++ }
++
++ /// @brief Buffer for a single socket read.
++ std::vector<uint8_t> input_buf_;
++};
++
++
++// Verifies that an ICMP socket can be opened and closed.
++TEST_F(ICMPSocketTest, openClose) {
++ SKIP_IF(notRoot());
++
++ // For open the endpoint is only used to determine protocol, the address is irrelevant.
++ ICMPEndpoint ping_to_endpoint(IOAddress::IPV4_ZERO_ADDRESS());
++
++ PingSocket socket(io_service_);
++ SocketCallback socket_cb("open");
++
++ // Verify the socket is closed.
++ ASSERT_FALSE(socket.isOpen());
++
++ // Open the socket.
++ ASSERT_NO_THROW_LOG(socket.open(&ping_to_endpoint, socket_cb));
++
++ // Verify the socket is open.
++ ASSERT_TRUE(socket.isOpen());
++ // Since open() is synchronous the callback should not have been invoked.
++ ASSERT_FALSE(socket_cb.getCalled());
++
++ // Opening an already open should be harmless.
++ ASSERT_NO_THROW_LOG(socket.open(&ping_to_endpoint, socket_cb));
++ ASSERT_TRUE(socket.isOpen());
++
++ // Close the socket.
++ ASSERT_NO_THROW_LOG(socket.close());
++ ASSERT_FALSE(socket.isOpen());
++
++ // Closing a closed socket should be harmless.
++ ASSERT_NO_THROW_LOG(socket.close());
++ ASSERT_FALSE(socket.isOpen());
++}
++
++// Verifies that an ICMP socket can send and receive ICMP messages.
++TEST_F(ICMPSocketTest, sendReceive) {
++ SKIP_IF(notRoot());
++
++ PingSocket socket(io_service_);
++
++ // For open the endpoint is only used to determine protocol, the address is irrelevant.
++ ICMPEndpoint endpoint(IOAddress::IPV4_ZERO_ADDRESS());
++
++ // Open the socket.
++ SocketCallback open_cb("open");
++ ASSERT_NO_THROW_LOG(socket.open(&endpoint, open_cb));
++
++ // Build a ping.
++ struct icmp echo;
++ memset(&echo, 0, sizeof(echo));
++ echo.icmp_type = ICMPMsg::ECHO_REQUEST;
++ echo.icmp_id = htons(0x1122);
++ echo.icmp_seq = htons(0x3344);
++ echo.icmp_cksum = htons(~(socket.calcChecksum((const uint8_t*)&echo, sizeof(echo))));
++
++ // Send it to the loopback.
++ IOAddress ping_to_addr("127.0.0.1");
++ SocketCallback send_cb("send");
++ ICMPEndpoint ping_to_endpoint(ping_to_addr);
++ ASSERT_NO_THROW_LOG(socket.asyncSend(&echo, sizeof(echo), &ping_to_endpoint, send_cb));
++
++ // Run the send handler.
++ io_service_->runOne();
++
++ // Callback should have been invoked without an error code.
++ ASSERT_TRUE(send_cb.getCalled());
++ ASSERT_EQ(0, send_cb.getCode());
++ // Verify we sent the whole message.
++ ASSERT_EQ(send_cb.getLength(), sizeof(echo));
++
++ // Call asyncReceive until we get our reply.
++ resizeInputBuf(1500);
++ ICMPEndpoint reply_endpoint;
++ SocketCallback receive_cb("receive");
++
++ // We need two receives when pinging loop back, only one with a real address.
++ size_t pass = 0;
++ do {
++ receive_cb.clear();
++ memset(getInputBufData(), 0x00, getInputBufSize());
++ ASSERT_NO_THROW(socket.asyncReceive(static_cast<void*>(getInputBufData()),
++ getInputBufSize(), 0, &reply_endpoint, receive_cb));
++
++ // Run the read handler.
++ io_service_->runOne();
++ } while (++pass < 2 && (!receive_cb.getCalled()));
++
++ // Callback should have been invoked without an error code.
++ ASSERT_TRUE(receive_cb.getCalled());
++ ASSERT_EQ(0, receive_cb.getCode());
++
++ // Verify the reply came from the target address.
++ EXPECT_EQ(ping_to_addr.toText(), reply_endpoint.getAddress().toText());
++
++ // Verify we got at least enough data for an IP header.
++ size_t bytes_received = receive_cb.getLength();
++ ASSERT_GE(bytes_received, sizeof(struct ip));
++
++ // Build the reply from data
++ uint8_t* icbuf = getInputBufData();
++
++ // Find the IP header length...
++ struct ip* ip_header = (struct ip*)(icbuf);
++ auto hlen = (ip_header->ip_hl << 2);
++
++ // Make sure we received enough data.
++ ASSERT_TRUE(bytes_received >= (hlen + sizeof(struct icmp)))
++ << "received packet too short to be ICMP";
++
++ // Verify the message type.
++ struct icmp* reply = (struct icmp*)(icbuf + hlen);
++ auto msg_type = reply->icmp_type;
++ ASSERT_EQ(ICMPMsg::ECHO_REPLY, msg_type);
++
++ // Verify the id and sequence values.
++ auto id = ntohs(reply->icmp_hun.ih_idseq.icd_id);
++ EXPECT_EQ(0x1122, id);
++
++ auto sequence = ntohs(reply->icmp_hun.ih_idseq.icd_seq);
++ EXPECT_EQ(0x3344, sequence);
++
++ // Close the socket.
++ ASSERT_NO_THROW_LOG(socket.close());
++ ASSERT_FALSE(socket.isOpen());
++}
++
++}
+diff --git a/src/hooks/dhcp/ping_check/tests/meson.build b/src/hooks/dhcp/ping_check/tests/meson.build
+new file mode 100644
+index 0000000000..8beca7813e
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/meson.build
+@@ -0,0 +1,21 @@
++if not TESTS_OPT.enabled()
++ subdir_done()
++endif
++
++dhcp_ping_check_tests = executable(
++ 'dhcp-ping-check-tests',
++ 'config_cache_unittests.cc',
++ 'icmp_endpoint_unittests.cc',
++ 'icmp_msg_unittests.cc',
++ 'icmp_socket_unittests.cc',
++ 'ping_channel_unittests.cc',
++ 'ping_check_config_unittests.cc',
++ 'ping_check_mgr_unittests.cc',
++ 'ping_context_store_unittests.cc',
++ 'ping_context_unittests.cc',
++ 'run_unittests.cc',
++ dependencies: [CRYPTO_DEP, GTEST_DEP],
++ include_directories: [include_directories('.'), include_directories('..')] + INCLUDES,
++ link_with: [dhcp_ping_check_archive] + LIBS_BUILT_SO_FAR,
++)
++test('dhcp-ping-check-tests', dhcp_ping_check_tests, protocol: 'gtest')
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_channel_unittests.cc b/src/hooks/dhcp/ping_check/tests/ping_channel_unittests.cc
+new file mode 100644
+index 0000000000..4c57a2e500
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_channel_unittests.cc
+@@ -0,0 +1,821 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the PingChannel class.
++
++#include <config.h>
++
++#include <ping_channel.h>
++#include <ping_test_utils.h>
++#include <asiolink/interval_timer.h>
++#include <asiolink/io_service_thread_pool.h>
++#include <dhcp/iface_mgr.h>
++#include <util/multi_threading_mgr.h>
++#include <testutils/multi_threading_utils.h>
++#include <testutils/gtest_utils.h>
++#include <gtest/gtest.h>
++
++#include <boost/multi_index/indexed_by.hpp>
++#include <boost/multi_index/member.hpp>
++#include <boost/multi_index/mem_fun.hpp>
++#include <boost/multi_index/hashed_index.hpp>
++#include <boost/multi_index/ordered_index.hpp>
++#include <boost/multi_index_container.hpp>
++#include <boost/multi_index/composite_key.hpp>
++
++#include <queue>
++#include <list>
++#include <thread>
++#include <mutex>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::ping_check;
++using namespace isc::util;
++using namespace isc::test;
++using namespace boost::asio::error;
++
++namespace ph = std::placeholders;
++
++namespace {
++
++/// @brief Tag for index by address.
++struct AddressIdSequenceIndexTag { };
++
++/// @brief A multi index container holding pointers ICMPMsgPtr
++///
++/// The message may be accessed using the following index(es):
++/// - using an IPv4 address, id, and sequence number
++typedef boost::multi_index_container<
++ // It holds pointers to ICMPMsg objects.
++ ICMPMsgPtr,
++ boost::multi_index::indexed_by<
++ // Specification of the first index starts here.
++ // This index sorts PingContexts by IPv4 addresses represented as
++ // IOAddress objects.
++ // Specification of the first index starts here.
++ boost::multi_index::ordered_unique<
++ boost::multi_index::tag<AddressIdSequenceIndexTag>,
++ boost::multi_index::composite_key<
++ ICMPMsg,
++ // The boolean value specifying if context is waiting for a reply
++ boost::multi_index::const_mem_fun<ICMPMsg, const IOAddress&,
++ &ICMPMsg::getSource>,
++ boost::multi_index::const_mem_fun<ICMPMsg, uint16_t,
++ &ICMPMsg::getId>,
++ boost::multi_index::const_mem_fun<ICMPMsg, uint16_t,
++ &ICMPMsg::getSequence>
++ >
++ >
++ >
++> ReplyContainer;
++
++/// @brief Single-threaded test fixture for exercising a PingChannel.
++class PingChannelTest : public IOServiceTest {
++public:
++ /// @brief Constructor
++ PingChannelTest() : mutex_(new mutex()), stopped_(false) {
++ MultiThreadingMgr::instance().setMode(false);
++ };
++
++ /// @brief Destructor
++ virtual ~PingChannelTest() {
++ stopped_ = true;
++ if (channel_) {
++ channel_->close();
++ }
++ if (ios_pool_) {
++ ios_pool_->getIOService()->stopAndPoll();
++ ios_pool_->stop();
++ }
++ ios_pool_.reset();
++ test_timer_.cancel();
++ test_io_service_->stopAndPoll();
++ MultiThreadingMgr::instance().setMode(false);
++ }
++
++ /// @brief Called prior to test destruction.
++ /// Ensure we stop the pool in the even a test failed in an unexpected
++ /// manner that left it running. Otherwise we can get false TSAN complaints.
++ virtual void TearDown() {
++ // Stop the thread pool (if one).
++ if (ios_pool_) {
++ ios_pool_->stop();
++ }
++ }
++
++ /// @brief Initializes the IOServiceThreadPool
++ ///
++ /// @param num_threads number of threads in the pool
++ /// @param defer_start enables deferred start of the pool's IOService
++ void initThreadPool(size_t num_threads = 1, bool defer_start = false) {
++ ios_pool_.reset(new IoServiceThreadPool(IOServicePtr(), num_threads, defer_start));
++ };
++
++ /// @brief Callback to invoke to fetch the next ping target.
++ ///
++ /// Fetches the next entry from the front of the send queue (if one). Checks for
++ /// test completion before returning.
++ ///
++ /// @param[out] next upon return it will contain the next target address. Contents are
++ /// only meaningful if the function returns true.
++ ///
++ /// @return True another target address exists, false otherwise.
++ virtual bool nextToSend(IOAddress& next) {
++ if (stopped_) {
++ return (false);
++ }
++ MultiThreadingLock lock(*mutex_);
++ bool use_next = true;
++ if (send_queue_.empty()) {
++ use_next = false;
++ } else {
++ next = send_queue_.front();
++ }
++
++ stopIfDone();
++ return (use_next);
++ }
++
++ /// @brief Callback to invoke when an ECHO write has completed.
++ ///
++ /// Ensures the completed echo matches the front of the send queue and then
++ /// pops it from the front of the queue. Checks for test completion before
++ /// returning.
++ ///
++ /// @param echo ICMP echo message that as sent
++ virtual void echoSent(ICMPMsgPtr& echo, bool send_failed) {
++ if (stopped_) {
++ return;
++ }
++ MultiThreadingLock lock(*mutex_);
++ ASSERT_EQ(echo->getDestination(), send_queue_.front()) << "send queue mismatch";
++ send_queue_.pop();
++ if (!send_failed) {
++ echos_sent_.push_back(echo);
++ }
++ stopIfDone();
++ }
++
++ /// @brief Callback to invoke when an ICMP reply has been received.
++ ///
++ /// Stores the reply if it is an ECHO REPLY message. We check to the
++ /// do avoid storing our outbound ECHO REQUESTs when testing with loop back
++ /// address. Checks for test completion before returning.
++ ///
++ /// @param reply ICMP message that was received
++ virtual void replyReceived(ICMPMsgPtr& reply) {
++ if (stopped_) {
++ return;
++ }
++ MultiThreadingLock lock(*mutex_);
++ if (reply->getType() == ICMPMsg::ECHO_REPLY) {
++ // If loopback routing is enabled, Insert the original destination address
++ // as the reply's source address.
++ if (channel_->route_loopback_) {
++ IOAddress address = channel_->loopback_map_.find(reply->getSequence());
++ if (address != IOAddress::IPV4_ZERO_ADDRESS()) {
++ reply->setSource(address);
++ }
++ }
++
++ replies_received_.push_back(reply);
++ storeReply(reply);
++ }
++
++ stopIfDone();
++ }
++
++ /// @brief Tests that a channel can send and receive, reliably
++ /// in either single or multi-threaded mode.
++ ///
++ /// The test queues the given number of requests, beginning with
++ /// address 127.0.0.1 and incrementing the address through the number
++ /// of targets. It then opens the channel and initiates reading and
++ /// and writing, running until the test completes or times out.
++ /// It expects to receive a reply for every request.
++ ///
++ /// @param num_threads number of threads in the thread pool. If 0,
++ /// the channel will be single-threaded, sharing the test's IOService,
++ /// otherwise the channel will be driven by an IOServiceThreadPool with
++ /// the given number of threads.
++ /// @param num_targets number of target IP addresses to ping. Must not
++ /// be greater than 253.
++ /// @param set_error_trigger optional function that sets the error trigger
++ /// condition.
++ void sendReceiveTest(size_t num_threads, size_t num_targets = 25,
++ const std::function<void()>& set_error_trigger = [](){});
++
++ /// @brief Tests for graceful behavior when a channel encounters a read
++ /// or write error, in either single or multi-threaded mode.
++ ///
++ /// The test runs in two passes. The first pass sends and receives until
++ /// the error trigger occurs. The error should induce a graceful cessation
++ /// of operations. After verifying expected state of affairs, the second pass
++ /// is begun by re-opening the channel and resuming operations until the test
++ /// completes or times out.
++ ///
++ /// @param set_error_trigger function that sets the error trigger condition
++ /// @param num_threads number of threads in the thread pool. If 0,
++ /// the channel will be single-threaded, sharing the test's IOService,
++ /// otherwise the channel will be driven by an IOServiceThreadPool with
++ /// the given number of threads.
++ /// @param num_targets number of target IP addresses to ping. Must not
++ /// be greater than 253.
++ void ioErrorTest(const std::function<void()>& set_error_trigger,
++ size_t num_threads, size_t num_targets = 10);
++
++ /// @brief Adds a reply to reply store.
++ ///
++ /// Fails if a reply for the same address, id, and sequence number is already
++ /// in the store. Must be used in a thread-safe context.
++ ///
++ /// @param reply reply to store
++ void storeReply(ICMPMsgPtr& reply) {
++ auto retpair = replies_map_.insert(reply);
++ ASSERT_TRUE(retpair.second)
++ << "failed to insert reply for: " << reply->getSource()
++ << ", id: " << reply->getId() << ", sequence: " << reply->getSequence();
++ }
++
++ /// @brief Fetches a reply from the store that matches a given ECHO
++ ///
++ /// Must be used in a thread-safe context.
++ ///
++ /// @param echo echo for whom a reply is sought
++ ///
++ /// @return The matching reply if found, otherwise an empty ICMPMsgPtr.
++ ICMPMsgPtr findReply(const ICMPMsgPtr& echo) {
++ auto const& index = replies_map_.get<AddressIdSequenceIndexTag>();
++ auto key = boost::make_tuple(echo->getDestination(), echo->getId(), echo->getSequence());
++ auto iter = index.find(key);
++ return (iter == index.end() ? ICMPMsgPtr() : *iter);
++ }
++
++ /// @brief Channel instance.
++ TestablePingChannelPtr channel_;
++
++ /// @brief IoServiceThreadPool instance
++ IoServiceThreadPoolPtr ios_pool_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++
++ /// @brief Queue of IOAddresses for which to send ECHO REQUESTs.
++ std::queue<IOAddress> send_queue_;
++
++ /// @brief List of ECHO REQUESTs that have been successfully sent in the order
++ /// they were sent.
++ std::list<ICMPMsgPtr> echos_sent_;
++
++ /// @brief List of ECHO REPLYs that have been successfully received in the
++ /// order they were received.
++ std::list<ICMPMsgPtr> replies_received_;
++
++ /// @brief Map of ECHO REPLYs received, indexed by source IP, id, and sequence number.
++ ReplyContainer replies_map_;
++
++ /// @brief Flag which indicates that the manager has been stopped.
++ bool stopped_;
++};
++
++void
++PingChannelTest::sendReceiveTest(size_t num_threads, size_t num_targets /* = 25 */,
++ const std::function<void()>& set_error_trigger) {
++ stopped_ = false;
++
++ // Clear state.
++ send_queue_ = {};
++ echos_sent_.clear();
++ replies_received_.clear();
++ replies_map_.clear();
++
++ SKIP_IF(notRoot());
++
++ ASSERT_TRUE(num_targets < 253);
++ auto channel_ios = test_io_service_;
++ if (num_threads) {
++ // Enable MT mode.
++ util::MultiThreadingMgr::instance().setMode(true);
++
++ // Initialize the thread pool to num_threads, defer start.
++ ASSERT_NO_THROW_LOG(initThreadPool(num_threads, true));
++ ASSERT_TRUE(ios_pool_->isStopped());
++ channel_ios = ios_pool_->getIOService();
++ }
++
++ // Create the channel instance with the appropriate io_service.
++ ASSERT_NO_THROW_LOG(channel_.reset(new TestablePingChannel(
++ channel_ios,
++ std::bind(&PingChannelTest::nextToSend, this, ph::_1),
++ std::bind(&PingChannelTest::echoSent, this, ph::_1, ph::_2),
++ std::bind(&PingChannelTest::replyReceived, this, ph::_1)
++ )));
++
++ // Create the callback to check test completion criteria.
++ // It returns true if we have sent out all the echos and received
++ // all the replies.
++ test_done_cb_ = [this]() {
++ return (send_queue_.empty() && (echos_sent_.size() == replies_received_.size()));
++ };
++
++ // Fill the send queue with num_target addresses to ping.
++ IOAddress target("127.0.0.1");
++ for (auto i = 0; i < num_targets; ++i) {
++ send_queue_.push(target);
++ target = IOAddress::increase(target);
++ }
++
++ (set_error_trigger)();
++
++ // Open the channel.
++ ASSERT_NO_THROW_LOG(channel_->open());
++ ASSERT_TRUE(channel_->isOpen());
++
++ if (num_threads) {
++ ios_pool_->run();
++ }
++
++ // Initiate reading and writing.
++ ASSERT_NO_THROW_LOG(channel_->startRead());
++ ASSERT_NO_THROW_LOG(channel_->startSend());
++
++ // Run the main thread's IOService until we complete or timeout.
++ ASSERT_NO_THROW_LOG(runIOService(1000));
++
++ if (ios_pool_) {
++ // Stop the thread pool.
++ ASSERT_NO_THROW_LOG(ios_pool_->stop());
++ ASSERT_TRUE(ios_pool_->isStopped());
++ }
++
++ // Send queue should be empty.
++ EXPECT_TRUE(send_queue_.empty());
++
++ // Should have as many replies as echos.
++ EXPECT_EQ(echos_sent_.size(), replies_received_.size());
++
++ // Should have a reply for every echo.
++ for (auto const& echo : echos_sent_) {
++ ICMPMsgPtr reply = findReply(echo);
++ EXPECT_TRUE(reply) << "no reply found for:" << echo->getDestination()
++ << ", id:" << echo->getId() << ", sequence: " << echo->getSequence();
++ }
++
++ stopped_ = true;
++ if (channel_) {
++ channel_->close();
++ }
++ if (ios_pool_) {
++ ios_pool_->getIOService()->stopAndPoll();
++ ios_pool_->stop();
++ }
++ ios_pool_.reset();
++ test_timer_.cancel();
++ test_io_service_->stopAndPoll();
++ MultiThreadingMgr::instance().setMode(false);
++}
++
++void
++PingChannelTest::ioErrorTest(const std::function<void()>& set_error_trigger,
++ size_t num_threads, size_t num_targets) {
++ ASSERT_TRUE(num_targets < 253);
++ SKIP_IF(notRoot());
++
++ ASSERT_TRUE(replies_received_.empty());
++
++ /// If it's an MT test create the thread pool.
++ auto channel_ios = test_io_service_;
++ if (num_threads) {
++ // Enable MT mode.
++ util::MultiThreadingMgr::instance().setMode(true);
++
++ // Initialize the thread pool to num_threads, defer start.
++ ASSERT_NO_THROW_LOG(initThreadPool(num_threads, true));
++ ASSERT_TRUE(ios_pool_->isStopped());
++ channel_ios = ios_pool_->getIOService();
++ }
++
++ // Set local shutdown called flag to false.
++ bool shutdown_cb_called = false;
++
++ // Create the channel instance with the appropriate io_service.
++ ASSERT_NO_THROW_LOG(channel_.reset(new TestablePingChannel(
++ channel_ios,
++ std::bind(&PingChannelTest::nextToSend, this, ph::_1),
++ std::bind(&PingChannelTest::echoSent, this, ph::_1, ph::_2),
++ std::bind(&PingChannelTest::replyReceived, this, ph::_1),
++ ([this, &shutdown_cb_called]() {
++ shutdown_cb_called = true;
++ test_io_service_->stop();
++ })
++ )));
++
++ // Set the test_done_cb_ to always return false (i.e. test is not
++ // done).
++ test_done_cb_ = []() {
++ return (false);
++ };
++
++ // Fill the send queue with target addresses to ping.
++ IOAddress target("127.0.0.1");
++ for (auto i = 0; i < (num_targets / 2); ++i) {
++ send_queue_.push(target);
++ target = IOAddress::increase(target);
++ }
++
++ // Set the error trigger.
++ (set_error_trigger)();
++
++ // FIRST PASS
++
++ // Open the channel.
++ ASSERT_NO_THROW_LOG(channel_->open());
++ ASSERT_TRUE(channel_->isOpen());
++
++ if (num_threads) {
++ ios_pool_->run();
++ }
++
++ // Initiate reading and writing.
++ ASSERT_NO_THROW_LOG(channel_->startRead());
++ ASSERT_NO_THROW_LOG(channel_->startSend());
++
++ // Run the main thread's IOService until we stop or timeout.
++ ASSERT_NO_THROW_LOG(runIOService(1000));
++
++ // Shutdown callback should have been invoked, the channel should be closed,
++ // but the pool should still be running.
++ ASSERT_TRUE(shutdown_cb_called);
++ ASSERT_FALSE(channel_->isOpen());
++
++ if (ios_pool_) {
++ ASSERT_TRUE(ios_pool_->isRunning());
++
++ // Pause the thread pool.
++ ASSERT_NO_THROW_LOG(ios_pool_->pause());
++ ASSERT_TRUE(ios_pool_->isPaused());
++ }
++
++ // Save how many echos sent and replies received during the first pass.
++ auto first_pass_echo_count = echos_sent_.size();
++ auto first_pass_reply_count = replies_received_.size();
++
++ // Should have sent some but not all.
++ EXPECT_LE(first_pass_echo_count, num_targets);
++
++ // SECOND PASS
++
++ // Modify the test done callback to check test completion criteria.
++ // It returns true if we have sent out all the echos and received
++ // all the replies.
++ test_done_cb_ = [this, &first_pass_reply_count]() {
++ return (send_queue_.empty() && (replies_received_.size() > first_pass_reply_count));
++ };
++
++ // Fill the send queue with target addresses to ping.
++ for (auto i = 0; i < (num_targets / 2); ++i) {
++ send_queue_.push(target);
++ target = IOAddress::increase(target);
++ }
++
++ // Resume running the thread pool (if one).
++ if (ios_pool_) {
++ ASSERT_NO_THROW_LOG(ios_pool_->run());
++ ASSERT_TRUE(ios_pool_->isRunning());
++ }
++
++ // Resume reopening the channel and restarting IO operations.
++ ASSERT_NO_THROW_LOG(channel_->open());
++ ASSERT_TRUE(channel_->isOpen());
++ ASSERT_NO_THROW_LOG(channel_->startRead());
++ ASSERT_NO_THROW_LOG(channel_->startSend());
++
++ // Run the main thread's IOService until we complete or timeout.
++ ASSERT_NO_THROW_LOG(runIOService(1000));
++
++ // Stop the thread pool (if one).
++ if (ios_pool_) {
++ ASSERT_NO_THROW_LOG(ios_pool_->stop());
++ ASSERT_TRUE(ios_pool_->isStopped());
++ }
++
++ // Send queue should be empty.
++ EXPECT_TRUE(send_queue_.empty());
++
++ // Should have sent as many echos as we queued.
++ EXPECT_EQ(echos_sent_.size(), num_targets);
++
++ // Should have more replies than we had, but likely not all.
++ EXPECT_GE(replies_received_.size(), first_pass_reply_count);
++}
++
++// Verifies PingChannel open and close operations.
++TEST_F(PingChannelTest, openCloseST) {
++ SKIP_IF(notRoot());
++
++ // Create the channel instance.
++ ASSERT_NO_THROW_LOG(channel_.reset(new TestablePingChannel(
++ test_io_service_,
++ std::bind(&PingChannelTest::nextToSend, this, ph::_1),
++ std::bind(&PingChannelTest::echoSent, this, ph::_1, ph::_2),
++ std::bind(&PingChannelTest::replyReceived, this, ph::_1)
++ )));
++
++ ASSERT_TRUE(channel_);
++
++ ASSERT_TRUE(channel_->getSingleThreaded());
++
++ // Verify it is not open.
++ ASSERT_FALSE(channel_->isOpen());
++
++ EXPECT_FALSE(channel_->getWatchSocket());
++ EXPECT_EQ(channel_->getRegisteredWriteFd(), -1);
++ EXPECT_EQ(channel_->getRegisteredReadFd(), -1);
++
++ // Verify that invoking close is harmless.
++ ASSERT_NO_THROW_LOG(channel_->close());
++
++ // Attempt to open the channel.
++ ASSERT_NO_THROW_LOG(channel_->open());
++
++ // PingChannel::open() is synchronous and while it has a callback
++ // it should never be invoked. Run the service to make sure.
++ ASSERT_NO_THROW_LOG(runIOService(1000));
++
++ // Verify the channel is open.
++ ASSERT_TRUE(channel_->isOpen());
++
++ // Verify the WatchSocket was created and that its fd and that of the
++ // PingSocket are both registered with IfaceMgr.
++ ASSERT_TRUE(channel_->getWatchSocket());
++ int registered_write_fd = channel_->getRegisteredWriteFd();
++ EXPECT_EQ(registered_write_fd, channel_->getWatchSocket()->getSelectFd());
++ EXPECT_TRUE(IfaceMgr::instance().isExternalSocket(registered_write_fd));
++ int registered_read_fd = channel_->getRegisteredReadFd();
++ EXPECT_EQ(registered_read_fd, channel_->getPingSocket()->getNative());
++ EXPECT_TRUE(IfaceMgr::instance().isExternalSocket(registered_read_fd));
++
++ // A subsequent open should be harmless.
++ ASSERT_NO_THROW_LOG(channel_->open());
++
++ // Closing the socket should work.
++ ASSERT_NO_THROW_LOG(channel_->close());
++
++ // Verify watch socket is gone, registered fds are reset, and prior
++ // registered fds are no longer registered.
++ EXPECT_FALSE(channel_->getWatchSocket());
++ EXPECT_EQ(channel_->getRegisteredWriteFd(), -1);
++ EXPECT_FALSE(IfaceMgr::instance().isExternalSocket(registered_write_fd));
++ EXPECT_EQ(channel_->getRegisteredReadFd(), -1);
++ EXPECT_FALSE(IfaceMgr::instance().isExternalSocket(registered_read_fd));
++
++ // Verify it is not open.
++ ASSERT_FALSE(channel_->isOpen());
++}
++
++// Verifies PingChannel open and close operations.
++TEST_F(PingChannelTest, openCloseMT) {
++ SKIP_IF(notRoot());
++ MultiThreadingTest mt;
++
++ // Create the channel instance.
++ ASSERT_NO_THROW_LOG(channel_.reset(new TestablePingChannel(
++ test_io_service_,
++ std::bind(&PingChannelTest::nextToSend, this, ph::_1),
++ std::bind(&PingChannelTest::echoSent, this, ph::_1, ph::_2),
++ std::bind(&PingChannelTest::replyReceived, this, ph::_1)
++ )));
++
++ ASSERT_TRUE(channel_);
++
++ ASSERT_FALSE(channel_->getSingleThreaded());
++
++ // Verify it is not open.
++ ASSERT_FALSE(channel_->isOpen());
++
++ // Verify that invoking close is harmless.
++ ASSERT_NO_THROW_LOG(channel_->close());
++
++ // Attempt to open the channel.
++ ASSERT_NO_THROW_LOG(channel_->open());
++
++ // PingChannel::open() is synchronous and while it has a callback
++ // it should never be invoked. Run the service to make sure.
++ ASSERT_NO_THROW_LOG(runIOService(1000));
++
++ // Verify the channel is open.
++ ASSERT_TRUE(channel_->isOpen());
++
++ // Verify that single-threaded members are not set.
++ EXPECT_FALSE(channel_->getWatchSocket());
++ EXPECT_EQ(channel_->getRegisteredWriteFd(), -1);
++ EXPECT_EQ(channel_->getRegisteredReadFd(), -1);
++
++ // A subsequent open should be harmless.
++ ASSERT_NO_THROW_LOG(channel_->open());
++
++ // Closing the socket should work.
++ ASSERT_NO_THROW_LOG(channel_->close());
++
++ // Verify it is not open.
++ ASSERT_FALSE(channel_->isOpen());
++}
++
++// Verifies that a PingChannel can perpetuate sending requests and receiving
++// replies when driven by a single-threaded IOService.
++TEST_F(PingChannelTest, sendReceiveST) {
++ sendReceiveTest(0);
++}
++
++// Verifies that a PingChannel can perpetuate sending requests and receiving
++// replies when driven by a multi-threaded IOServiceThreadPool 3 threads
++TEST_F(PingChannelTest, sendReceiveMT) {
++ // Use a thread pool with 3 threads.
++ sendReceiveTest(3);
++}
++
++// Verifies that an exception throw from asyncRead triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, readExceptionErrorST) {
++ ioErrorTest(
++ [this]() {
++ channel_->throw_on_read_number_ = 5;
++ }, 0);
++}
++
++// Verifies that an exception throw from asyncRead triggers graceful channel
++// shutdown and that operations can be resumed with a multi-threaded channel.
++TEST_F(PingChannelTest, readExceptionErrorMT) {
++ // Use a thread pool with 3 threads.
++ ioErrorTest(
++ [this]() {
++ channel_->throw_on_read_number_ = 5;
++ }, 3, 20);
++}
++
++// Verifies that a fatal error code passed into socketReadCallback triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, readFatalErrorST) {
++ ioErrorTest(
++ [this]() {
++ channel_->ec_on_read_number_ = 3;
++ // See boost/asio/error.hpp for error codes
++ channel_->read_error_ec_ = make_error_code(fault);
++ }, 0);
++}
++
++// Verifies that a fatal error code passed into socketReadCallback triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, readFatalErrorMT) {
++ ioErrorTest(
++ [this]() {
++ channel_->ec_on_read_number_ = 3;
++ // See boost/asio/error.hpp for error codes
++ channel_->read_error_ec_ = make_error_code(fault);
++ }, 4);
++}
++
++// Verifies that a non-fatal, EWOULDBLOCK error passed into socketReadCallback does
++// not disrupt reading for a single-threaded channel.
++TEST_F(PingChannelTest, readAgainErrorST) {
++ sendReceiveTest(0, 10,
++ [this]() {
++ channel_->ec_on_read_number_ = 4;
++ // See boost/asio/error.hpp for error codes
++ channel_->read_error_ec_ = make_error_code(would_block);
++ });
++}
++
++// Verifies that a non-fatal, EWOULDBLOCK error passed into socketReadCallback does
++// not disrupt reading for a multi-threaded channel.
++TEST_F(PingChannelTest, readAgainErrorMT) {
++ sendReceiveTest(3, 10,
++ [this]() {
++ channel_->ec_on_read_number_ = 4;
++ // See boost/asio/error.hpp for error codes
++ channel_->read_error_ec_ = make_error_code(would_block);
++ });
++}
++
++// Verifies that an exception throw from asyncRead triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, writeExceptionErrorST) {
++ ioErrorTest(
++ [this]() {
++ channel_->throw_on_write_number_ = 5;
++ }, 0);
++}
++
++// Verifies that an exception throw from asyncRead triggers graceful channel
++// shutdown and that operations can be resumed with a multi-threaded channel.
++TEST_F(PingChannelTest, writeExceptionErrorMT) {
++ // Use a thread pool with 3 threads.
++ ioErrorTest(
++ [this]() {
++ channel_->throw_on_write_number_ = 5;
++ }, 3);
++}
++
++// Verifies that a fatal error code passed into socketReadCallback triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, writeFatalErrorST) {
++ ioErrorTest(
++ [this]() {
++ channel_->ec_on_write_number_ = 3;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(fault);
++ }, 0);
++}
++
++// Verifies that a fatal error code passed into socketReadCallback triggers graceful channel
++// shutdown and that operations can be resumed with a single-threaded channel.
++TEST_F(PingChannelTest, writeFatalErrorMT) {
++ ioErrorTest(
++ [this]() {
++ channel_->ec_on_write_number_ = 3;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(fault);
++ }, 4);
++}
++
++// Verifies that a non-fatal, EWOULDBLOCK error passed into socketWriteCallback does
++// not disrupt writing for a single-threaded channel.
++TEST_F(PingChannelTest, writeAgainErrorST) {
++ sendReceiveTest(0, 10,
++ [this]() {
++ channel_->ec_on_write_number_ = 6;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(would_block);
++ });
++}
++
++// Verifies that a non-fatal, EWOULDBLOCK error passed into socketWriteCallback
++// does not disrupt writing for a multi-threaded channel.
++TEST_F(PingChannelTest, writeAgainErrorMT) {
++ sendReceiveTest(3, 10,
++ [this]() {
++ channel_->ec_on_write_number_ = 6;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(would_block);
++ });
++}
++
++// Verify the recoverable write errors do not disrupt writing for a
++// single-threaded channel.
++TEST_F(PingChannelTest, writeSendFailedErrorST) {
++ SKIP_IF(notRoot());
++
++ std::list<boost::asio::error::basic_errors> errors = {
++ boost::asio::error::network_unreachable,
++ boost::asio::error::host_unreachable,
++ boost::asio::error::network_down,
++ boost::asio::error::no_buffer_space,
++ boost::asio::error::access_denied
++ };
++
++ for (auto const& error : errors) {
++ sendReceiveTest(0, 10,
++ [this, error]() {
++ channel_->ec_on_write_number_ = 6;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(error);
++ });
++
++ // Sanity check, we should have sent one less than we targeted.
++ EXPECT_EQ(echos_sent_.size(), 9);
++ }
++}
++
++// Verify the recoverable write errors do not disrupt writing for a
++// multi-threaded channel.
++TEST_F(PingChannelTest, writeSendFailedErrorMT) {
++ SKIP_IF(notRoot());
++
++ std::list<boost::asio::error::basic_errors> errors = {
++ boost::asio::error::network_unreachable,
++ boost::asio::error::host_unreachable,
++ boost::asio::error::network_down,
++ boost::asio::error::no_buffer_space,
++ boost::asio::error::access_denied
++ };
++
++ for (auto const& error : errors) {
++ sendReceiveTest(3, 10,
++ [this, error]() {
++ channel_->ec_on_write_number_ = 6;
++ // See boost/asio/error.hpp for error codes
++ channel_->write_error_ec_ = make_error_code(error);
++ });
++
++ // Sanity check, we should have sent one less than we targeted.
++ EXPECT_EQ(echos_sent_.size(), 9);
++ }
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_check_config_unittests.cc b/src/hooks/dhcp/ping_check/tests/ping_check_config_unittests.cc
+new file mode 100644
+index 0000000000..a831a0efab
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_check_config_unittests.cc
+@@ -0,0 +1,287 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the PingCheckConfig class.
++
++#include <config.h>
++#include <ping_check_config.h>
++#include <testutils/gtest_utils.h>
++
++#include <gtest/gtest.h>
++#include <list>
++
++using namespace std;
++using namespace isc;
++using namespace isc::data;
++using namespace isc::ping_check;
++
++namespace {
++
++// Verifies PingCheckConfig constructors and accessors.
++TEST(PingCheckConfigTest, basics) {
++ PingCheckConfig config;
++
++ // Verify initial values.
++ EXPECT_TRUE(config.getEnablePingCheck());
++ EXPECT_EQ(1, config.getMinPingRequests());
++ EXPECT_EQ(100, config.getReplyTimeout());
++ EXPECT_EQ(60, config.getPingClttSecs());
++ EXPECT_EQ(0, config.getPingChannelThreads());
++
++ // Verify accessors.
++ EXPECT_NO_THROW_LOG(config.setEnablePingCheck(false));
++ EXPECT_FALSE(config.getEnablePingCheck());
++
++ EXPECT_NO_THROW_LOG(config.setMinPingRequests(4));
++ EXPECT_EQ(4, config.getMinPingRequests());
++
++ EXPECT_NO_THROW_LOG(config.setReplyTimeout(250));
++ EXPECT_EQ(250, config.getReplyTimeout());
++
++ EXPECT_NO_THROW_LOG(config.setPingClttSecs(120));
++ EXPECT_EQ(120, config.getPingClttSecs());
++
++ EXPECT_NO_THROW_LOG(config.setPingChannelThreads(6));
++ EXPECT_EQ(6, config.getPingChannelThreads());
++
++ // Verify copy construction.
++ PingCheckConfig config2(config);
++ EXPECT_FALSE(config2.getEnablePingCheck());
++ EXPECT_EQ(4, config2.getMinPingRequests());
++ EXPECT_EQ(250, config2.getReplyTimeout());
++ EXPECT_EQ(120, config2.getPingClttSecs());
++ EXPECT_EQ(6, config2.getPingChannelThreads());
++}
++
++// Exercises PingCheckConfig parameter parsing with valid configuration
++// permutations.
++TEST(PingCheckConfigTest, parseValidScenarios) {
++ // Describes a test scenario.
++ struct Scenario {
++ int line_; // Scenario line number
++ std::string json_; // JSON configuration to parse
++ bool exp_enable_ping_check_; // Expected value for enable-ping-check
++ uint32_t exp_min_ping_requests_; // Expected value for min-ping-requests
++ uint32_t exp_reply_timeout_; // Expected value for reply-timeout
++ uint32_t exp_ping_cltt_secs_; // Expected value for ping-cltt-secs
++ size_t exp_num_threads_; // Expected value for ping-channel-threads
++ };
++
++ // List of test scenarios to run.
++ list<Scenario> scenarios = {
++ {
++ // Empty map
++ __LINE__,
++ R"({ })",
++ true, 1, 100, 60, 0
++ },
++ {
++ // Only enable-ping-check",
++ __LINE__,
++ R"({ "enable-ping-check" : false })",
++ false, 1, 100, 60, 0
++ },
++ {
++ // Only min-ping-requests",
++ __LINE__,
++ R"({ "min-ping-requests" : 3 })",
++ true, 3, 100, 60, 0
++ },
++ {
++ // Only reply-timeout",
++ __LINE__,
++ R"({ "reply-timeout" : 250 })",
++ true, 1, 250, 60, 0
++ },
++ {
++ // Only ping-cltt-secs",
++ __LINE__,
++ R"({ "ping-cltt-secs" : 77 })",
++ true, 1, 100, 77, 0
++ },
++ {
++ // Only ping-channel-threads",
++ __LINE__,
++ R"({ "ping-channel-threads" : 5 })",
++ true, 1, 100, 60, 5
++ },
++ {
++ // All parameters",
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 2,
++ "reply-timeout" : 375,
++ "ping-cltt-secs" : 120,
++ "ping-channel-threads" : 6
++ })",
++ false, 2, 375, 120, 6
++ },
++ };
++
++ // Iterate over the scenarios.
++ for (auto const& scenario : scenarios) {
++ stringstream oss;
++ oss << "scenario at line: " << scenario.line_;
++ SCOPED_TRACE(oss.str());
++
++ // Convert JSON texts to Element map.
++ ConstElementPtr json_elements;
++ ASSERT_NO_THROW_LOG(json_elements = Element::fromJSON(scenario.json_));
++
++ // Parsing elements should succeed.
++ PingCheckConfig config;
++ ASSERT_NO_THROW_LOG(config.parse(json_elements));
++
++ // Verify expected values.
++ EXPECT_EQ(scenario.exp_enable_ping_check_, config.getEnablePingCheck());
++ EXPECT_EQ(scenario.exp_min_ping_requests_, config.getMinPingRequests());
++ EXPECT_EQ(scenario.exp_reply_timeout_, config.getReplyTimeout());
++ EXPECT_EQ(scenario.exp_ping_cltt_secs_, config.getPingClttSecs());
++ EXPECT_EQ(scenario.exp_num_threads_, config.getPingChannelThreads());
++ }
++}
++
++// Exercises PingCheckConfig parameter parsing with invalid configuration
++// permutations.
++TEST(PingCheckConfigTest, parseInvalidScenarios) {
++ // Describes a test scenario.
++ struct Scenario {
++ int line_; // Scenario line number
++ string json_; // JSON configuration to parse
++ string exp_message_; // Expected exception message
++ };
++
++ // List of test scenarios to run. Most scenario supply
++ // all valid parameters except one in error. This allows
++ // us to verify that no values are changed if any are in error.
++ list<Scenario> scenarios = {
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 3,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4,
++ "bogus" : false
++ })",
++ "spurious 'bogus' parameter"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : "not bool",
++ "min-ping-requests" : 3,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4
++ })",
++ "'enable-ping-check' parameter is not a boolean"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 0,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4
++ })",
++ "invalid min-ping-requests: '0', must be greater than 0"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : -2,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4
++ })",
++ "invalid min-ping-requests: '-2', must be greater than 0"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 1,
++ "reply-timeout" : 0,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4
++ })",
++ "invalid reply-timeout: '0', must be greater than 0"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 1,
++ "reply-timeout" : -77,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 4
++ })",
++ "invalid reply-timeout: '-77', must be greater than 0"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 1,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : -3,
++ "ping-channel-threads" : 4
++ })",
++ "invalid ping-cltt-secs: '-3', cannot be less than 0"
++ },
++ {
++ __LINE__,
++ R"(
++ {
++ "enable-ping-check" : false,
++ "min-ping-requests" : 1,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : -1
++ })",
++ "invalid ping-channel-threads: '-1', cannot be less than 0"
++ }
++ };
++
++ // Iterate over the scenarios.
++ PingCheckConfig default_config;
++ for (auto const& scenario : scenarios) {
++ stringstream oss;
++ oss << "scenario at line: " << scenario.line_;
++ SCOPED_TRACE(oss.str());
++
++ // Convert JSON text to a map of parameters.
++ ConstElementPtr json_elements;
++ ASSERT_NO_THROW_LOG(json_elements = Element::fromJSON(scenario.json_));
++
++ // Parsing parameters should throw.
++ PingCheckConfig config;
++ ASSERT_THROW_MSG(config.parse(json_elements), dhcp::DhcpConfigError,
++ scenario.exp_message_);
++
++ // Original values should be intact.
++ EXPECT_EQ(default_config.getEnablePingCheck(), config.getEnablePingCheck());
++ EXPECT_EQ(default_config.getMinPingRequests(), config.getMinPingRequests());
++ EXPECT_EQ(default_config.getReplyTimeout(), config.getReplyTimeout());
++ EXPECT_EQ(default_config.getPingClttSecs(), config.getPingClttSecs());
++ EXPECT_EQ(default_config.getPingChannelThreads(), config.getPingChannelThreads());
++ }
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_check_mgr_unittests.cc b/src/hooks/dhcp/ping_check/tests/ping_check_mgr_unittests.cc
+new file mode 100644
+index 0000000000..ded13b085c
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_check_mgr_unittests.cc
+@@ -0,0 +1,1878 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the PingCheckMgr class.
++#include <config.h>
++
++#include <ping_check_mgr.h>
++#include <ping_test_utils.h>
++#include <cc/data.h>
++#include <dhcp/pkt4.h>
++#include <dhcpsrv/cfgmgr.h>
++#include <dhcpsrv/lease.h>
++#include <hooks/hooks_manager.h>
++#include <util/chrono_time_utils.h>
++#include <testutils/gtest_utils.h>
++#include <testutils/multi_threading_utils.h>
++
++#include <gtest/gtest.h>
++#include <mutex>
++#include <chrono>
++
++using namespace std;
++using namespace isc;
++using namespace isc::data;
++using namespace isc::dhcp;
++using namespace isc::util;
++using namespace isc::asiolink;
++using namespace isc::ping_check;
++using namespace isc::hooks;
++using namespace isc::test;
++using namespace std::chrono;
++using namespace boost::asio::error;
++
++namespace ph = std::placeholders;
++
++namespace {
++
++// Sanity check the basics for production class, PingCheckMgr, single-threaded mode.
++TEST(PingCheckMgr, basicsST) {
++ SKIP_IF(IOServiceTest::notRoot());
++ MultiThreadingMgr::instance().setMode(false);
++
++ // Create a multi-threaded manager.
++ IOServicePtr main_ios(new IOService());
++ PingCheckMgrPtr mgr;
++ ASSERT_NO_THROW_LOG(mgr.reset(new PingCheckMgr(0)));
++ ASSERT_TRUE(mgr);
++ mgr->setIOService(main_ios);
++
++ // Sanity check the global configuration. More robust tests are done
++ // elsewhere.
++ auto& config = mgr->getGlobalConfig();
++ EXPECT_TRUE(config->getEnablePingCheck());
++ EXPECT_EQ(1, config->getMinPingRequests());
++ EXPECT_EQ(100, config->getReplyTimeout());
++ EXPECT_EQ(60, config->getPingClttSecs());
++ EXPECT_EQ(0, config->getPingChannelThreads());
++
++ // Verify we report as stopped.
++ EXPECT_FALSE(mgr->isRunning());
++ EXPECT_TRUE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Starting it should be OK.
++ ASSERT_NO_THROW_LOG(mgr->start());
++
++ // Verify we report as running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Pausing it should be harmless.
++ ASSERT_NO_THROW_LOG(mgr->pause());
++
++ // Verify we report as running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Resuming it should be harmless.
++ ASSERT_NO_THROW_LOG(mgr->resume());
++
++ // Verify we report as running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Stopping it should be fine
++ ASSERT_NO_THROW_LOG(mgr->stop());
++
++ // Verify we report as stopped.
++ EXPECT_FALSE(mgr->isRunning());
++ EXPECT_TRUE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Re-starting it should be OK.
++ ASSERT_NO_THROW_LOG(mgr->start());
++
++ // Verify we report as running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Calling destructor when its running should be OK.
++ ASSERT_NO_THROW_LOG(mgr.reset());
++
++ main_ios->stopAndPoll();
++}
++
++// Sanity check the basics for production class, PingCheckMgr. Bulk of testing
++// is done with test derivation, TestPingCheckMgr.
++TEST(PingCheckMgr, basicsMT) {
++ SKIP_IF(IOServiceTest::notRoot());
++ MultiThreadingTest mt;
++
++ // Create a multi-threaded manager.
++ IOServicePtr main_ios(new IOService());
++ PingCheckMgrPtr mgr;
++ ASSERT_NO_THROW_LOG(mgr.reset(new PingCheckMgr(3)));
++ ASSERT_TRUE(mgr);
++ mgr->setIOService(main_ios);
++
++ // Sanity check the global configuration. More robust tests are done
++ // elsewhere.
++ auto& config = mgr->getGlobalConfig();
++ EXPECT_TRUE(config->getEnablePingCheck());
++ EXPECT_EQ(1, config->getMinPingRequests());
++ EXPECT_EQ(100, config->getReplyTimeout());
++ EXPECT_EQ(60, config->getPingClttSecs());
++ EXPECT_EQ(3, config->getPingChannelThreads());
++
++ // It should not be running yet.
++ EXPECT_FALSE(mgr->isRunning());
++ EXPECT_TRUE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Starting it should be OK.
++ ASSERT_NO_THROW_LOG(mgr->start());
++
++ // Verify it's running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Pausing it should be fine.
++ ASSERT_NO_THROW_LOG(mgr->pause());
++
++ // Verify it's paused.
++ EXPECT_FALSE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_TRUE(mgr->isPaused());
++
++ // Resuming it should be fine.
++ ASSERT_NO_THROW_LOG(mgr->resume());
++
++ // Verify it's running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Stopping it should be fine
++ ASSERT_NO_THROW_LOG(mgr->stop());
++
++ // It should not be running.
++ EXPECT_FALSE(mgr->isRunning());
++ EXPECT_TRUE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Re-starting it should be OK.
++ ASSERT_NO_THROW_LOG(mgr->start());
++
++ // Verify it's running.
++ EXPECT_TRUE(mgr->isRunning());
++ EXPECT_FALSE(mgr->isStopped());
++ EXPECT_FALSE(mgr->isPaused());
++
++ // Calling destructor when its running should be OK.
++ ASSERT_NO_THROW_LOG(mgr.reset());
++}
++
++// Verify basic behavior of PingCheckMgr::configure().
++TEST(PingCheckMgr, configure) {
++ // Create a manager.
++ IOServicePtr main_ios(new IOService());
++ PingCheckMgrPtr mgr;
++ ASSERT_NO_THROW_LOG(mgr.reset(new PingCheckMgr()));
++ ASSERT_TRUE(mgr);
++
++ // Verify initial global configuration.
++ auto& default_config = mgr->getGlobalConfig();
++ EXPECT_TRUE(default_config->getEnablePingCheck());
++ EXPECT_EQ(1, default_config->getMinPingRequests());
++ EXPECT_EQ(100, default_config->getReplyTimeout());
++ EXPECT_EQ(60, default_config->getPingClttSecs());
++ EXPECT_EQ(0, default_config->getPingChannelThreads());
++
++ //Create a valid configuration.
++ std::string valid_json_cfg =
++ R"({
++ "enable-ping-check" : false,
++ "min-ping-requests" : 2,
++ "reply-timeout" : 250,
++ "ping-cltt-secs" : 90,
++ "ping-channel-threads" : 3
++ })";
++
++ auto parameters = Element::fromJSON(valid_json_cfg);
++
++ // Parse it.
++ ASSERT_NO_THROW_LOG(mgr->configure(parameters));
++
++ // Verify updated global configuration.
++ auto& config = mgr->getGlobalConfig();
++ ASSERT_TRUE(config);
++ EXPECT_FALSE(config->getEnablePingCheck());
++ EXPECT_EQ(2, config->getMinPingRequests());
++ EXPECT_EQ(250, config->getReplyTimeout());
++ EXPECT_EQ(90, config->getPingClttSecs());
++ EXPECT_EQ(3, config->getPingChannelThreads());
++
++ // Create an invalid configuration.
++ std::string invalid_json_cfg =
++ R"({
++ "enable-ping-check" : true,
++ "min-ping-requests" : 4,
++ "reply-timeout" : 500,
++ "ping-cltt-secs" : 45,
++ "ping-channel-threads" : 6,
++ "bogus" : 0
++ })";
++
++ parameters = Element::fromJSON(invalid_json_cfg);
++
++ // Parsing it should throw.
++ ASSERT_THROW_MSG(mgr->configure(parameters), DhcpConfigError, "spurious 'bogus' parameter");
++
++ // Verify configuration values were left unchanged.
++ auto& final_config = mgr->getGlobalConfig();
++ ASSERT_TRUE(final_config);
++ EXPECT_EQ(final_config->getEnablePingCheck(), config->getEnablePingCheck());
++ EXPECT_EQ(final_config->getMinPingRequests(), config->getMinPingRequests());
++ EXPECT_EQ(final_config->getReplyTimeout(), config->getReplyTimeout());
++ EXPECT_EQ(final_config->getPingClttSecs(), config->getPingClttSecs());
++ EXPECT_EQ(final_config->getPingChannelThreads(), config->getPingChannelThreads());
++}
++
++/// @brief Defines a callback to invoke at the bottom of sendCompleted()
++typedef std::function<void(const ICMPMsgPtr& echo, bool send_failed)> SendCompletedCallback;
++
++/// @brief Defines a callback to invoke at the bottom of replyReceived()
++typedef std::function<void(const ICMPMsgPtr& reply)> ReplyReceivedCallback;
++
++/// @brief Testable derivation of PingCheckMgr
++///
++/// Uses a TestablePingChannel to facilitate more robust testing.
++class TestablePingCheckMgr : public PingCheckMgr {
++public:
++ /// @brief Constructor.
++ ///
++ /// @param num_threads number of threads to use in the thread pool (0 means follow
++ /// core thread pool size)
++ /// @param min_echos minimum number of ECHO REQUESTs sent without replies
++ /// received required to declare an address free to offer. Defaults to 1,
++ /// must be greater than zero.
++ /// @param reply_timeout maximum number of milliseconds to wait for an
++ /// ECHO REPLY after an ECHO REQUEST has been sent. Defaults to 100,
++ TestablePingCheckMgr(uint32_t num_threads, uint32_t min_echos = 1,
++ uint32_t reply_timeout = 100)
++ : PingCheckMgr(num_threads, min_echos, reply_timeout),
++ post_send_completed_cb_(SendCompletedCallback()),
++ post_reply_received_cb_(ReplyReceivedCallback()) {
++ }
++
++ /// @brief Destructor.
++ virtual ~TestablePingCheckMgr() {
++ post_send_completed_cb_ = SendCompletedCallback();
++ post_reply_received_cb_ = ReplyReceivedCallback();
++ if (getIOService()) {
++ getIOService()->stopAndPoll();
++ }
++ }
++
++ /// @brief Fetch the current channel instance.
++ ///
++ /// @return pointer to the TestablePingChannel instance (or an empty pointer).
++ TestablePingChannelPtr getChannel() {
++ return (boost::dynamic_pointer_cast<TestablePingChannel>(channel_));
++ }
++
++ /// @brief Fetches the manager's context store.
++ ///
++ /// @return Pointer to the PingContextStore.
++ PingContextStorePtr getStore() {
++ return (store_);
++ }
++
++ /// @brief Fetches the expiration timer's current interval (in milliseconds).
++ ///
++ /// @return current interval as long or 0L if the timer is not currently
++ /// running or does not exist.
++ long getExpirationTimerInterval() {
++ if (expiration_timer_) {
++ return (expiration_timer_->getInterval());
++ }
++
++ return (0);
++ }
++
++protected:
++ /// @brief Creates a TestablePingChannel instance.
++ ///
++ /// This override the base case creator.
++ ///
++ /// @param io_service IOService that will drive the channel.
++ /// @return pointer to the newly created channel.
++ virtual PingChannelPtr createChannel(asiolink::IOServicePtr io_service) {
++ return (TestablePingChannelPtr(
++ new TestablePingChannel(io_service,
++ std::bind(&PingCheckMgr::nextToSend, this, ph::_1),
++ std::bind(&TestablePingCheckMgr::sendCompleted,
++ this, ph::_1, ph::_2),
++ std::bind(&TestablePingCheckMgr::replyReceived, this, ph::_1),
++ std::bind(&PingCheckMgr::channelShutdown, this))));
++ }
++
++public:
++ /// @brief Fetches the current size of the parking lot.
++ ///
++ /// @return size_t containing the number of entries parked.
++ size_t parkingLotSize() const {
++ auto const& parking_lot = ServerHooks::getServerHooks().getParkingLotPtr("lease4_offer");
++ return (parking_lot->size());
++ }
++
++ /// @brief Callback passed to PingChannel to invoke when an ECHO REQUEST
++ /// send has completed.
++ ///
++ /// -# Invokes the base class implementation
++ /// -# Invokes an optional callback
++ ///
++ /// @param echo ICMP echo message that is sent.
++ /// @param send_failed True if the send completed with a non-fatal error,
++ /// false otherwise.
++ virtual void sendCompleted(const ICMPMsgPtr& echo, bool send_failed) {
++ // Call the production callback.
++ PingCheckMgr::sendCompleted(echo, send_failed);
++
++ // Invoke the post check, if one.
++ if (post_send_completed_cb_) {
++ (post_send_completed_cb_)(echo, send_failed);
++ }
++ }
++
++ /// @brief Callback invoked by the channel to process received ICMP messages.
++ ///
++ /// -# Invokes the base class implementation
++ /// -# Pauses the test IOService thread and returns if the parking lot is empty
++ /// -# Invokes an option callback passing in the reply received
++ ///
++ /// @param reply pointer to the ICMP message received.
++ virtual void replyReceived(const ICMPMsgPtr& reply) {
++ if (reply->getType() == ICMPMsg::ECHO_REQUEST) {
++ return;
++ }
++
++ // If we're routing loopback messages, look up the original address based
++ // on the sequence number and use it as the reply's source address.
++ if (getChannel()->route_loopback_) {
++ IOAddress address = getChannel()->loopback_map_.find(reply->getSequence());
++ if (address != IOAddress::IPV4_ZERO_ADDRESS()) {
++ reply->setSource(address);
++ }
++ }
++
++ // Call the production callback.
++ PingCheckMgr::replyReceived(reply);
++
++ // Invoke the post check, if one.
++ if (post_reply_received_cb_) {
++ (post_reply_received_cb_)(reply);
++ }
++ }
++
++ /// @brief Fetches the thread pool (if it exists).
++ ///
++ /// @return pointer to theIoServiceThreadPool. Will be empty
++ /// in ST mode or if the manager has not been started.
++ asiolink::IoServiceThreadPoolPtr getThreadPool() {
++ return (thread_pool_);
++ }
++
++ /// @brief Sets the network_state object.
++ ///
++ /// @param network_state pointer to a NetworkState instance.
++ void setNetworkState(NetworkStatePtr network_state) {
++ network_state_ = network_state;
++ }
++
++ /// @brief Callback to invoke at the bottom of sendCompleted().
++ SendCompletedCallback post_send_completed_cb_;
++
++ /// @brief Callback to invoke at the bottom of replyReceived().
++ ReplyReceivedCallback post_reply_received_cb_;
++};
++
++/// @brief Defines a shared pointer to a PingCheckMgr.
++typedef boost::shared_ptr<TestablePingCheckMgr> TestablePingCheckMgrPtr;
++
++/// @brief Holds a lease and its associated query.
++struct LeaseQueryPair {
++public:
++ /// @brief Constructor.
++ ///
++ /// @param lease pointer to the lease.
++ /// @param query pointer to the query.
++ LeaseQueryPair(Lease4Ptr lease, Pkt4Ptr query) : lease_(lease), query_(query) {
++ };
++
++ /// @brief Pointer to the lease.
++ Lease4Ptr lease_;
++
++ /// @brief Pointer to the query.
++ Pkt4Ptr query_;
++};
++
++/// @brief Container of leases and their associated queries.
++typedef std::vector<LeaseQueryPair> LeaseQueryPairs;
++
++/// @brief Test fixture for exercising PingCheckMgr.
++///
++/// Uses a TestablePingCheckMgr instance for all tests and
++/// provides numerous helper functions.
++class PingCheckMgrTest : public IOServiceTest {
++public:
++ /// @brief Constructor.
++ PingCheckMgrTest() : mgr_(), lease_query_pairs_(), mutex_(new mutex()),
++ test_start_time_(PingContext::now()), unparked_(0) {
++ MultiThreadingMgr::instance().setMode(false);
++ };
++
++ /// @brief Destructor.
++ virtual ~PingCheckMgrTest() {
++ test_timer_.cancel();
++ test_io_service_->stopAndPoll();
++ MultiThreadingMgr::instance().setMode(false);
++ }
++
++ /// @brief Pretest setup.
++ ///
++ /// Registers the hook point and creates its parking lot.
++ virtual void SetUp() {
++ HooksManager::registerHook("lease4_offer");
++ parking_lot_ = boost::make_shared<ParkingLotHandle>(
++ ServerHooks::getServerHooks().getParkingLotPtr("lease4_offer"));
++ }
++
++ /// @brief Ensure we stop cleanly.
++ virtual void TearDown() {
++ if (mgr_) {
++ mgr_->stop();
++ }
++
++ HooksManager::clearParkingLots();
++ }
++
++ /// @brief Creates the test's manager instance.
++ ///
++ /// @param num_threads number of threads in the thread pool.
++ /// @param min_echos minimum number of echos per ping check.
++ /// @param reply_timeout reply timeout per ping.
++ /// @param start_and_pause when false, the manager is only created,
++ /// when true it is created, started and then paused. This allows
++ /// manipulation of context store contents while the threads are doing
++ /// no work.
++ void createMgr(uint32_t num_threads,
++ uint32_t min_echos = 1,
++ uint32_t reply_timeout = 100,
++ bool start_and_pause = false) {
++ ASSERT_NO_THROW_LOG(
++ mgr_.reset(new TestablePingCheckMgr(num_threads, min_echos, reply_timeout)));
++ ASSERT_TRUE(mgr_);
++ mgr_->setIOService(test_io_service_);
++
++ if (start_and_pause) {
++ ASSERT_NO_THROW_LOG(mgr_->start());
++
++ if (!MultiThreadingMgr::instance().getMode()) {
++ ASSERT_FALSE(mgr_->getThreadPool());
++ } else {
++ ASSERT_TRUE(mgr_->getThreadPool());
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++ ASSERT_TRUE(mgr_->isPaused());
++ }
++ }
++ }
++
++ /// @brief Add a new lease and query pair to the test's list of lease query pairs.
++ ///
++ /// Creates a bare-bones DHCPv4 lease and DHCPDISCOVER, wraps them in a
++ /// LeaseQueryPair and adds the pair to the end of the test's internal
++ /// list of pairs, lease_query_pairs_.
++ ///
++ /// @param target IOAddress of the lease.
++ /// @param transid transaction id of the query.
++ ///
++ /// @return A copy of the newly created pair.
++ LeaseQueryPair makeLeaseQueryPair(IOAddress target, uint16_t transid) {
++ // Make a lease and query pair
++ Lease4Ptr lease(new Lease4());
++ lease->addr_ = IOAddress(target);
++ Pkt4Ptr query(new Pkt4(DHCPDISCOVER, transid));
++ LeaseQueryPair lqp(lease, query);
++ lease_query_pairs_.push_back(lqp);
++ return (lqp);
++ }
++
++ /// @brief Start ping checks for a given number of targets.
++ ///
++ /// The function first creates and parks the given number of targets, and
++ /// then starts a ping check for each of them. Parking them all first
++ /// establishes the number of ping checks expected to be conducted during
++ /// the test prior to actually starting any of them. This avoids the
++ /// parking lot from becoming empty part way through the test.
++ ///
++ /// It unpark callback lambda increments the unparked_ counter and then
++ /// pushes the unparked lease/query pair to either the list of frees
++ /// or list of declines.
++ ///
++ /// @param num_targets number of target ip addresses to ping check.
++ /// @param start_address starting target address. Defaults to 127.0.0.1.
++ ///
++ /// @return last target address started.
++ IOAddress startTargets(size_t num_targets, IOAddress start_address = IOAddress("127.0.0.1")) {
++ IOAddress target = start_address;
++ for (auto i = 0; i < num_targets; ++i) {
++ auto lqp = makeLeaseQueryPair(IOAddress(target), i+1);
++ HooksManager::park("lease4_offer", lqp.query_,
++ [this, lqp]() {
++ MultiThreadingLock lock(*mutex_);
++ ++unparked_;
++ auto handle = lqp.query_->getCalloutHandle();
++ bool offer_address_in_use;
++ handle->getArgument("offer_address_in_use", offer_address_in_use);
++ offer_address_in_use ? declines_.push_back(lqp) : frees_.push_back(lqp);
++ });
++
++ try {
++ mgr_->startPing(lqp.lease_, lqp.query_, parking_lot_);
++ } catch (const std::exception& ex) {
++ ADD_FAILURE() << "startPing threw: " << ex.what();
++ }
++
++ target = IOAddress::increase(target);
++ }
++
++ return(target);
++ }
++
++ /// @brief Fetches the context, by lease address, from the store for a
++ /// given lease query pair.
++ ///
++ /// @param lqp LeaseQueryPair for which the context is desired.
++ /// @return pointer to the found context or an empty pointer.
++ PingContextPtr getContext(const LeaseQueryPair& lqp) {
++ return (getContext(lqp.lease_->addr_));
++ }
++
++ /// @brief Fetches the context, by lease address, from the store for address.
++ ///
++ /// @param address lease ip address for which the context is desired.
++ /// @return pointer to the found context or an empty pointer.
++ PingContextPtr getContext(const IOAddress& address) {
++ return (mgr_->getStore()->getContextByAddress(address));
++ }
++
++ /// @brief Updates a context in the store.
++ ///
++ /// @param context context to update.
++ void updateContext(PingContextPtr& context) {
++ ASSERT_NO_THROW_LOG(mgr_->getStore()->updateContext(context));
++ }
++
++ /// @brief Tests equality of two timestamps within a given tolerance.
++ ///
++ /// The two time stamps are considered equal if the absolute value of their
++ /// difference is between 0 and the specified tolerance (inclusive).
++ ///
++ /// @param lhs first TimeStamp to compare.
++ /// @param rhs second TimeStamp to compare.
++ /// @param tolerance margin of difference allowed for equality in milliseconds.
++ /// Defaults to 10.
++ ///
++ /// @return True if the time stamps are "equal", false otherwise.
++ bool fuzzyEqual(const TimeStamp& lhs, const TimeStamp& rhs, long tolerance = 10) {
++ auto diff = abs(duration_cast<milliseconds>(lhs - rhs).count());
++ return (diff >= 0 && diff <= tolerance);
++ }
++
++ /// @brief Tests equality of two longs within a given tolerance.
++ ///
++ /// The two values are considered equal if the absolute value of their
++ /// difference is between 0 and the specified tolerance (inclusive).
++ ///
++ /// @param lhs first value to compare.
++ /// @param rhs second value to compare.
++ /// @param tolerance margin of difference allowed for equality in milliseconds.
++ /// Defaults to 10.
++ ///
++ /// @return True if the time values are "equal", false otherwise.
++ bool fuzzyEqual(const long& lhs, const long& rhs, long tolerance = 10) {
++ auto diff = abs(lhs - rhs);
++ return (diff >= 0 && diff <= tolerance);
++ }
++
++ /// @brief Creates an ECHO REQUEST message from a given address.
++ ///
++ /// @param target ip address to use as the echo's destination address.
++ /// @return Pointer to the new message.
++ ICMPMsgPtr makeEchoRequest(const IOAddress& target) {
++ ICMPMsgPtr msg(new ICMPMsg());
++ msg->setType(ICMPMsg::ECHO_REQUEST);
++ msg->setDestination(IOAddress(target));
++ msg->setSource(IOAddress("127.0.0.1"));
++ return (msg);
++ }
++
++ /// @brief Creates an ECHO_REPLY message from a given address.
++ ///
++ /// @param from ip address to use as the reply's source address.
++ /// @return Pointer to the new message.
++ ICMPMsgPtr makeEchoReply(const IOAddress& from) {
++ ICMPMsgPtr msg(new ICMPMsg());
++ msg->setType(ICMPMsg::ECHO_REPLY);
++ msg->setSource(IOAddress(from));
++ msg->setDestination(IOAddress("127.0.0.1"));
++ return (msg);
++ }
++
++ /// @brief Creates an TARGET_UNREACHABLE message from a given address.
++ ///
++ /// @param target ip address to use as the reply's source address.
++ /// @return Pointer to the new message.
++ ICMPMsgPtr makeUnreachable(const IOAddress& target) {
++ // Make the TARGET_UNREACHABLE message first.
++ ICMPMsgPtr msg(new ICMPMsg());
++ msg->setType(ICMPMsg::TARGET_UNREACHABLE);
++ msg->setSource(IOAddress("127.0.0.1"));
++ msg->setDestination(IOAddress("127.0.0.1"));
++
++ // Now embed the ping target's "original" echo into the unreachable
++ // message's payload. This includes the IP header followed by the
++ // ECHO REQUEST. First make the IP header and add it to the payload.
++ // We only set values we care about.
++ struct ip ip_header;
++ memset((void *)(&ip_header), 0x00, sizeof(struct ip));
++ ip_header.ip_v = 4;
++ ip_header.ip_hl = 5; /* shift left twice = 20 */
++ ip_header.ip_len = 48; /* ip_header + echo length */
++ ip_header.ip_dst.s_addr = htonl(target.toUint32());
++ ip_header.ip_src.s_addr = htonl(msg->getSource().toUint32());
++ msg->setPayload((const uint8_t*)(&ip_header), sizeof(struct ip));
++
++ // Now make the ECHO_REQUEST, pack it and add that to the payload.
++ ICMPMsgPtr echo = makeEchoRequest(target);
++ ICMPPtr packed_echo = echo->pack();
++ msg->setPayload((const uint8_t*)(packed_echo.get()), sizeof(struct icmp));
++
++ return (msg);
++ }
++
++ /// @brief Compares a LeaseQueryPair collection to the internal collection
++ /// of pairs created (see makeLeaseQueryPairs()).
++ ///
++ /// @param test_collection Collection of pairs to compare against those in
++ /// the creation collection.
++ void compareLeaseQueryPairs(LeaseQueryPairs& test_collection) {
++ // We should have as many in the test_collection as we have creation
++ // collection.
++ ASSERT_EQ(test_collection.size(), lease_query_pairs_.size());
++
++ // Order is not guaranteed so we sort both lists then compare.
++ std::sort(test_collection.begin(), test_collection.end(),
++ [](LeaseQueryPair const& a, LeaseQueryPair const& b)
++ { return (a.lease_->addr_ < b.lease_->addr_); });
++
++ std::sort(lease_query_pairs_.begin(), lease_query_pairs_.end(),
++ [](LeaseQueryPair const& a, LeaseQueryPair const& b)
++ { return (a.lease_->addr_ < b.lease_->addr_); });
++
++ auto dpi = test_collection.begin();
++ for (auto const& lqpi : lease_query_pairs_) {
++ ASSERT_EQ((*dpi).lease_->addr_, lqpi.lease_->addr_);
++ ++dpi;
++ }
++ }
++
++ /// @brief Exercises the operational basics: create, start, and stop
++ /// for TestablePingCheckMgr.
++ ///
++ /// @param num_threads number of threads in the thread pool.
++ void testOperationalBasics(size_t num_threads) {
++ SKIP_IF(notRoot());
++
++ // Create manager with the given number of threads.
++ ASSERT_NO_THROW_LOG(createMgr(num_threads));
++ ASSERT_TRUE(mgr_);
++
++ // Should not be running.
++ EXPECT_FALSE(mgr_->isRunning());
++ EXPECT_TRUE(mgr_->isStopped());
++ EXPECT_FALSE(mgr_->isPaused());
++
++ // Channel should not yet exist.
++ ASSERT_FALSE(mgr_->getChannel());
++
++ // Start the manager.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++
++ // Thread pool should exist in MT mode only.
++ if (MultiThreadingMgr::instance().getMode()) {
++ ASSERT_TRUE(mgr_->getThreadPool());
++ } else {
++ ASSERT_FALSE(mgr_->getThreadPool());
++ }
++
++ // Should be running.
++ EXPECT_TRUE(mgr_->isRunning());
++ EXPECT_FALSE(mgr_->isStopped());
++ EXPECT_FALSE(mgr_->isPaused());
++
++ // Channel should exist and be open.
++ auto channel = mgr_->getChannel();
++ ASSERT_TRUE(channel);
++ ASSERT_TRUE(channel->isOpen());
++
++ // Context store should exist and be empty.
++ auto store = mgr_->getStore();
++ ASSERT_TRUE(store);
++ auto pings = store->getAll();
++ ASSERT_EQ(0, pings->size());
++
++ // Destruction should be graceful.
++ ASSERT_NO_THROW_LOG(mgr_.reset());
++ }
++
++ /// @brief Verifies that startPing() creates a new context in the store and
++ /// it can be fetched with the nextToSend() callback.
++ void testStartPing() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 2, reply_timeout 250 ms.
++ // ST mode should ingore requested thread number.
++ ASSERT_NO_THROW_LOG(createMgr(3, 2, 250));
++ ASSERT_TRUE(mgr_);
++
++ // Make a lease and query pair
++ auto lqp1 = makeLeaseQueryPair(IOAddress("127.0.0.101"), 101);
++
++ // Channel isn't open, startPing should throw.
++ ASSERT_THROW_MSG(mgr_->startPing(lqp1.lease_, lqp1.query_, parking_lot_), InvalidOperation,
++ "PingCheckMgr::startPing() - channel isn't open");
++
++ // Start the manager. This will open the channel.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++ ASSERT_TRUE(mgr_->isRunning());
++
++ if (mgr_->getThreadPool()) {
++ // Pause the manager so startPing() will succeed but no events will occur.
++ // This should let us add contexts that sit in WAITING_TO_SEND state.
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++ ASSERT_TRUE(mgr_->isPaused());
++ }
++
++ // Call startPing() again. It should work.
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp1.lease_, lqp1.query_, parking_lot_));
++
++ // Calling startPing() on the same lease should fail, duplicates not allowed.
++ ASSERT_THROW_MSG(mgr_->startPing(lqp1.lease_, lqp1.query_, parking_lot_), DuplicateContext,
++ "PingContextStore::addContex: context already exists for: 127.0.0.101");
++
++ // Our context should be present.
++ auto const& store = mgr_->getStore();
++ auto pings = store->getAll();
++ ASSERT_EQ(1, pings->size());
++ PingContextPtr context1;
++ ASSERT_NO_THROW_LOG(context1 = store->getContextByAddress(lqp1.lease_->addr_));
++ ASSERT_TRUE(context1);
++
++ // Verify the context's state.
++ EXPECT_EQ(2, context1->getMinEchos());
++ EXPECT_EQ(250, context1->getReplyTimeout());
++ EXPECT_EQ(0, context1->getEchosSent());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context1->getLastEchoSentTime());
++ EXPECT_LE(test_start_time_, context1->getSendWaitStart());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context1->getNextExpiry());
++ EXPECT_LE(test_start_time_, context1->getCreatedTime());
++ EXPECT_EQ(lqp1.lease_, context1->getLease());
++ EXPECT_EQ(lqp1.query_, context1->getQuery());
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, context1->getState());
++
++ // Sleep a bit to make sure there's a difference in context times.
++ usleep(5);
++
++ // Make a second lease and query pair
++ auto lqp2 = makeLeaseQueryPair(IOAddress("127.0.0.102"), 102);
++
++ // Start a ping for lease2.
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp2.lease_, lqp2.query_, parking_lot_));
++
++ // Both contexts should be present.
++ pings = store->getAll();
++ ASSERT_EQ(2, pings->size());
++
++ // Fetch the second context by address.
++ PingContextPtr context2;
++ ASSERT_NO_THROW_LOG(context2 = store->getContextByAddress(lqp2.lease_->addr_));
++ ASSERT_TRUE(context2);
++
++ // Verify the second context's state.
++ EXPECT_EQ(2, context2->getMinEchos());
++ EXPECT_EQ(250, context2->getReplyTimeout());
++ EXPECT_EQ(0, context2->getEchosSent());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context2->getLastEchoSentTime());
++ // Its send_wait_start_time_ should be more recent than context1.
++ EXPECT_LE(context1->getSendWaitStart(), context2->getSendWaitStart());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context2->getNextExpiry());
++ // Its created_time_ should be more recent than context1.
++ EXPECT_LE(context1->getCreatedTime(), context2->getCreatedTime());
++ EXPECT_EQ(lqp2.lease_, context2->getLease());
++ EXPECT_EQ(lqp2.query_, context2->getQuery());
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, context2->getState());
++ }
++
++ /// @brief Exercises PingCheckMgr::nextToSend().
++ void testNextToSend() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 2 echos, 250 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 2, 250, true);
++
++ // Calling nextToSend() should return false.
++ IOAddress next("0.0.0.0");
++ ASSERT_FALSE(mgr_->nextToSend(next));
++
++ // Now let's start 3 contexts.
++ size_t num_targets = 3;
++ IOAddress target("127.0.0.1");
++ for (auto i = 0; i < num_targets; ++i) {
++ auto lqp = makeLeaseQueryPair(IOAddress(target), i+1);
++
++ // Call startPing().
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp.lease_, lqp.query_, parking_lot_));
++ target = IOAddress::increase(target);
++
++ PingContextPtr context = getContext(lqp);
++ ASSERT_TRUE(context);
++
++ // Verify the context's initial state is correct.
++ EXPECT_EQ(0, context->getEchosSent());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getLastEchoSentTime());
++ EXPECT_LE(test_start_time_, context->getSendWaitStart());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getNextExpiry());
++ EXPECT_LE(test_start_time_, context->getCreatedTime());
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++
++ // Sleep a few before we add the next one to ensure ordering by
++ // time is consistent.
++ usleep(5);
++ }
++
++ // Consecutive calls to nextToSend() should return target addresses
++ // in the order they were created.
++ for (auto const& lqp : lease_query_pairs_) {
++ // Next to send should return the next address to send.
++ ASSERT_TRUE(mgr_->nextToSend(next));
++
++ // It should match the lease as created.
++ ASSERT_EQ(next, lqp.lease_->addr_);
++
++ // Fetch the corresponding context.
++ PingContextPtr context = getContext(next);
++ ASSERT_TRUE(context);
++
++ // Verify the state has properly moved to SENDING.
++ EXPECT_EQ(0, context->getEchosSent());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getLastEchoSentTime());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getNextExpiry());
++ EXPECT_EQ(PingContext::SENDING, context->getState());
++ }
++
++ // A final call to nextToSend should return false.
++ ASSERT_FALSE(mgr_->nextToSend(next));
++ }
++
++ /// @brief Exercises PingCheckMgr::setNextExpiration.
++ void testSetNextExpiration() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 2 echos, 500 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 2, 500, true);
++
++ // Should not have an expiration time, timer should not be running.
++ ASSERT_EQ(PingContext::EMPTY_TIME(), mgr_->getNextExpiry());
++ ASSERT_EQ(mgr_->getExpirationTimerInterval(), 0);
++
++ // Now let's start 3 contexts.
++ size_t num_targets = 3;
++ IOAddress target("127.0.0.1");
++ for (auto i = 0; i < num_targets; ++i) {
++ auto lqp = makeLeaseQueryPair(IOAddress(target), i+1);
++
++ // Call startPing().
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp.lease_, lqp.query_, parking_lot_));
++ target = IOAddress::increase(target);
++ }
++
++ // Still should not have an expiration time nor running timer.
++ ASSERT_EQ(PingContext::EMPTY_TIME(), mgr_->getNextExpiry());
++ EXPECT_EQ(mgr_->getExpirationTimerInterval(), 0);
++
++ // Simulate a completed send for the second context.
++ PingContextPtr context2;
++ context2 = getContext(lease_query_pairs_[1]);
++ ASSERT_TRUE(context2);
++ context2->beginWaitingForReply(test_start_time_ - milliseconds(50));
++ updateContext(context2);
++
++ // Call setNextExpiration().
++ ASSERT_NO_THROW_LOG(mgr_->setNextExpiration());
++
++ // Refresh the context.
++ context2 = getContext(lease_query_pairs_[1]);
++
++ // Verify the mgr has the same next expiration as the context and
++ // that the expiration timer is running. Allow for some fudge in
++ // the checks.
++ auto original_mgr_expiry = mgr_->getNextExpiry();
++ EXPECT_TRUE(fuzzyEqual(original_mgr_expiry, context2->getNextExpiry()));
++
++ auto original_interval = mgr_->getExpirationTimerInterval();
++ EXPECT_TRUE(fuzzyEqual(original_interval, 450));
++
++ // Simulate a completed send for the third context.
++ PingContextPtr context3;
++ context3 = getContext(lease_query_pairs_[2]);
++ ASSERT_TRUE(context3);
++ context3->beginWaitingForReply();
++ updateContext(context3);
++
++ // Call setNextExpiration().
++ ASSERT_NO_THROW_LOG(mgr_->setNextExpiration());
++
++ // Refresh the context.
++ context3 = getContext(lease_query_pairs_[2]);
++
++ // Context3 should have a later expiration than context2.
++ EXPECT_LT(context2->getNextExpiry(), context3->getNextExpiry());
++
++ // Expiration and timer should still match the original values based on
++ // the second context.
++ EXPECT_TRUE(fuzzyEqual(mgr_->getNextExpiry(), original_mgr_expiry));
++ EXPECT_EQ(mgr_->getExpirationTimerInterval(), original_interval);
++
++ // Simulate a completed send for the first context but use a smaller
++ // timeout and back date it.
++ PingContextPtr context1;
++ context1 = getContext(lease_query_pairs_[0]);
++ ASSERT_TRUE(context1);
++ context1->setReplyTimeout(50);
++ context1->beginWaitingForReply(test_start_time_ - milliseconds(1));
++ updateContext(context1);
++
++ // Call setNextExpiration().
++ ASSERT_NO_THROW_LOG(mgr_->setNextExpiration());
++
++ // Refresh the context.
++ context1 = getContext(lease_query_pairs_[0]);
++
++ // Context1 should have a earlier expiration than context2.
++ EXPECT_LT(context1->getNextExpiry(), context2->getNextExpiry());
++ // Timer interval should be based on context1.
++ EXPECT_TRUE(fuzzyEqual(mgr_->getExpirationTimerInterval(), 50, 20))
++ << " interval: " << mgr_->getExpirationTimerInterval();
++
++ // Move all contexts to TARGET_FREE. This should leave none
++ // still waiting.
++ context1->setState(PingContext::TARGET_FREE);
++ updateContext(context1);
++ context2->setState(PingContext::TARGET_FREE);
++ updateContext(context2);
++ context3->setState(PingContext::TARGET_FREE);
++ updateContext(context3);
++
++ // Call setNextExpiration().
++ ASSERT_NO_THROW_LOG(mgr_->setNextExpiration());
++
++ // Should not have an expiration time, timer should not be running.
++ ASSERT_EQ(PingContext::EMPTY_TIME(), mgr_->getNextExpiry());
++ ASSERT_EQ(mgr_->getExpirationTimerInterval(), 0);
++ }
++
++ /// @brief Exercises PingCheckMgr::sendCompleted.
++ void testSendCompleted() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 2 echos, 500 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 2, 500, true);
++
++ // Start a ping for an address so we have a context.
++ IOAddress target("127.0.0.2");
++ auto lqp = makeLeaseQueryPair(IOAddress(target), 102);
++
++ // Call startPing().
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp.lease_, lqp.query_, parking_lot_));
++
++ // Simulate a completed send for the context.
++ PingContextPtr context;
++ context = getContext(lqp);
++ ASSERT_TRUE(context);
++
++ // Make an ECHO REQUEST packet based on context.
++ ICMPMsgPtr echo_request = makeEchoRequest(context->getLease()->addr_);
++
++ // Invoke sendCompleted() with fabricated request. Should succeed.
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(echo_request, false));
++
++ // Refresh the context.
++ context = getContext(context->getLease()->addr_);
++
++ EXPECT_EQ(PingContext::WAITING_FOR_REPLY, context->getState());
++ EXPECT_EQ(1, context->getEchosSent());
++ EXPECT_GE(context->getLastEchoSentTime(), test_start_time_);
++
++ // Verify the mgr has the same next expiration as the context and
++ // that the expiration timer is running. Allow for some fudge in
++ // the checks.
++ EXPECT_GT(context->getNextExpiry(), test_start_time_);
++ EXPECT_TRUE(fuzzyEqual(mgr_->getNextExpiry(), context->getNextExpiry()));
++ EXPECT_TRUE(fuzzyEqual(mgr_->getExpirationTimerInterval(), 500));
++
++ // Make an ECHO REQUEST packet for an address that has no context.
++ echo_request = makeEchoRequest(IOAddress("192.168.0.1"));
++
++ // Invoking sendCompleted() with request for a non-existent address be harmless.
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(echo_request, false));
++
++ // Invoking sendCompleted() with an invalid message type should be harmless.
++ echo_request->setType(ICMPMsg::ECHO_REPLY);
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(ICMPMsgPtr(), false));
++
++ // Invoking sendCompleted() with an empty message should be harmless.
++ echo_request.reset();
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(ICMPMsgPtr(), false));
++
++ // Verify expiration values should not have not been altered.
++ EXPECT_TRUE(fuzzyEqual(mgr_->getNextExpiry(), context->getNextExpiry()));
++ EXPECT_TRUE(fuzzyEqual(mgr_->getExpirationTimerInterval(), 500));
++ }
++
++ /// @brief Exercises PingCheckMgr::replyReceived() for ECHO REPLYs. Note this
++ /// also exercises handleEchoReply().
++ void testReplyReceivedForEchoReply() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 2 echos, 500 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 2, 500, true);
++
++ // Install a post reply received callback to stop the test if we're done.
++ mgr_->post_reply_received_cb_ =
++ [this](const ICMPMsgPtr& /* reply */) {
++ MultiThreadingLock lock(*mutex_);
++ if (mgr_->parkingLotSize() == 0) {
++ stopTestService();
++ return;
++ }
++ };
++
++ // Turn off loopback routing.
++ mgr_->getChannel()->route_loopback_ = false;
++
++ // Start a ping for an address so we have a context.
++ startTargets(1);
++ auto lqp = lease_query_pairs_[0];
++
++ // Simulate a completed send for the context.
++ PingContextPtr context;
++ context = getContext(lqp);
++ ASSERT_TRUE(context);
++
++ // Make an ECHO REQUEST packet based on context and invoke sendCompleted().
++ ICMPMsgPtr echo_request = makeEchoRequest(context->getLease()->addr_);
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(echo_request, false));
++
++ // Should still have one parked query.
++ EXPECT_EQ(1, mgr_->parkingLotSize());
++
++ // Verify the expiration timer is running.
++ EXPECT_TRUE(fuzzyEqual(mgr_->getExpirationTimerInterval(), 500));
++
++ // Make an ECHO REPLY packet based on context and invoke replyReceived().
++ ICMPMsgPtr echo_reply = makeEchoReply(context->getLease()->addr_);
++ ASSERT_NO_THROW_LOG(mgr_->replyReceived(echo_reply));
++
++ // Verify the expiration timer is no longer running.
++ EXPECT_EQ(mgr_->getExpirationTimerInterval(), 0);
++
++ // The context should no longer be in the store.
++ EXPECT_FALSE(getContext(lqp));
++
++ // We should have dropped the query from the lot rather than unparking it.
++ EXPECT_EQ(mgr_->parkingLotSize(), 0);
++ EXPECT_EQ(unparked_, 1);
++
++ // We should have one decline that matches our lease query pair.
++ compareLeaseQueryPairs(declines_);
++
++ // Make an ECHO REPLY packet for an address that has no context.
++ echo_reply = makeEchoReply(IOAddress("192.168.0.1"));
++
++ // Invoke replyReceived() for a reply with no matching context,
++ // it should not throw.
++ ASSERT_NO_THROW_LOG(mgr_->PingCheckMgr::replyReceived(echo_reply));
++
++ // Invoke replyReceived() an empty message, it should not throw.
++ // (Bypass test implementation for this check).
++ echo_reply.reset();
++ ASSERT_NO_THROW_LOG(mgr_->PingCheckMgr::replyReceived(echo_reply));
++ }
++
++ /// @brief Exercises PingCheckMgr::replyReceived() for UNREACHABLEs. Note this
++ /// also exercises handleTargetUnreachable().
++ void testReplyReceivedForTargetUnreachable() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 2 echos, 500 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 2, 500, true);
++
++ // Install a post reply received callback to stop the test if we're done.
++ mgr_->post_reply_received_cb_ =
++ [this](const ICMPMsgPtr& /* reply */) {
++ MultiThreadingLock lock(*mutex_);
++ if (mgr_->parkingLotSize() == 0) {
++ stopTestService();
++ return;
++ }
++ };
++
++ // Turn off loopback routing.
++ mgr_->getChannel()->route_loopback_ = false;
++
++ // Start a ping for an address so we have a context.
++ startTargets(1);
++ auto lqp = lease_query_pairs_[0];
++
++ // Simulate a completed send for the context.
++ PingContextPtr context;
++ context = getContext(lqp);
++ ASSERT_TRUE(context);
++
++ // Make an ECHO REQUEST packet based on context and invoke sendCompleted().
++ ICMPMsgPtr echo_request = makeEchoRequest(context->getLease()->addr_);
++ ASSERT_NO_THROW_LOG(mgr_->sendCompleted(echo_request, false));
++
++ // Should still have one parked query.
++ EXPECT_EQ(1, mgr_->parkingLotSize());
++
++ // Verify the expiration timer is running.
++ EXPECT_TRUE(fuzzyEqual(mgr_->getExpirationTimerInterval(), 500));
++
++ // Make an ECHO REPLY packet based on context and invoke replyReceived().
++ ICMPMsgPtr unreachable = makeUnreachable(context->getLease()->addr_);
++ ASSERT_NO_THROW_LOG(mgr_->replyReceived(unreachable));
++
++ // Verify the expiration timer is no longer running.
++ EXPECT_EQ(mgr_->getExpirationTimerInterval(), 0);
++
++ // The context should no longer be in the store.
++ EXPECT_FALSE(getContext(lqp));
++
++ // We should have unparked the query from the lot.
++ EXPECT_EQ(mgr_->parkingLotSize(), 0);
++ EXPECT_EQ(unparked_, 1);
++
++ // We should have one free that matches our lease query pair.
++ compareLeaseQueryPairs(frees_);
++
++ // Invoke replyReceived() for an unreachable with no matching context,
++ // it should not throw.
++ unreachable = makeUnreachable(IOAddress("192.168.0.1"));
++ ASSERT_NO_THROW_LOG(mgr_->replyReceived(unreachable));
++ }
++
++ /// @brief Verifies expiration processing by invoking expirationTimedout().
++ /// This also exercises processExpiredSince(), doNextEcho(), finishFree(),
++ /// and setNextExpiration().
++ void testExpirationProcessing() {
++ SKIP_IF(notRoot());
++
++ // Create a paused manager. 3 threads, 1 echos, 250 ms timeout.
++ // ST mode should ingore requested thread number.
++ createMgr(3, 1, 250, true);
++
++ // Start four ping checks, then stage them so:
++ //
++ // First context is WAITING_TO_SEND, no expiry.
++ // Second context is WAITING_FOR_REPLY, has expired and has
++ // exhausted min_echos_.
++ // Third context is WAITING_FOR_REPLY, has expired but has
++ // not exhausted min_echos_.
++ // Fourth context is WAITING_FOR_REPLY but has not yet expired.
++ //
++ size_t num_targets = 4;
++
++ // Start the desired number of targets with an unpark callback
++ // that increments the unparked count.
++ startTargets(num_targets);
++
++ // Now establish the desired state for each context.
++ // First context is in WAITING_TO_SEND, no expiry.
++ PingContextPtr context1 = getContext(lease_query_pairs_[0]);
++ ASSERT_TRUE(context1);
++ EXPECT_EQ(context1->getState(), PingContext::WAITING_TO_SEND);
++
++ // Second context setup: expired and has exhausted min_echos_
++ PingContextPtr context2 = getContext(lease_query_pairs_[1]);
++ ASSERT_TRUE(context2);
++ context2->beginWaitingForReply(test_start_time_ - milliseconds(500));
++ updateContext(context2);
++
++ // Third context setup: expired but has not exhausted min_echos_
++ PingContextPtr context3 = getContext(lease_query_pairs_[2]);
++ ASSERT_TRUE(context3);
++ context3->setMinEchos(2);
++ context3->beginWaitingForReply(test_start_time_ - milliseconds(500));
++ updateContext(context3);
++
++ // Fourth context setup: has not yet expired
++ PingContextPtr context4 = getContext(lease_query_pairs_[3]);
++ ASSERT_TRUE(context4);
++ context4->beginWaitingForReply(test_start_time_);
++ updateContext(context4);
++
++ // Now invoke expirationTimedout().
++ ASSERT_NO_THROW_LOG(mgr_->expirationTimedOut());
++
++ // Verify the contexts are in the expected states.
++ // Context1 should still be WAITING_TO_SEND.
++ context1 = getContext(lease_query_pairs_[0]);
++ ASSERT_TRUE(context1);
++ EXPECT_EQ(context1->getState(), PingContext::WAITING_TO_SEND);
++
++ // Context2 should be gone by unparking and its address freed.
++ IOAddress address = lease_query_pairs_[1].lease_->addr_;
++ context2 = getContext(address);
++ ASSERT_FALSE(context2);
++ EXPECT_EQ(unparked_, 1);
++ ASSERT_EQ(frees_.size(), 1);
++ EXPECT_EQ(frees_[0].lease_->addr_, address);
++
++ // Context3 should be in WAITING_TO_SEND.
++ context3 = getContext(lease_query_pairs_[2]);
++ ASSERT_TRUE(context3);
++ EXPECT_EQ(context3->getState(), PingContext::WAITING_TO_SEND);
++
++ // Context4 should still be WAITING_FOR_REPLY.
++ context4 = getContext(lease_query_pairs_[3]);
++ ASSERT_TRUE(context4);
++ EXPECT_EQ(context4->getState(), PingContext::WAITING_FOR_REPLY);
++
++ // Manager's next_expiry_ should be based on context4?
++ EXPECT_TRUE(fuzzyEqual(mgr_->getNextExpiry(), context4->getNextExpiry()));
++ }
++
++ /// @brief Generates a number of ping checks to local loop back addresses.
++ ///
++ /// Pings should all result in ECHO_REPLYs that get "declined". Declined
++ /// addresses are added to a list. Test completion is gated by the parking
++ /// lot becoming empty or test times out.
++ void testMultiplePingsWithReply() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 1,
++ // reply_timeout 1000 milliseconds. Larger time out for this test
++ // avoids sporadic expirations which leads to unaccounted for UNPARKs.
++ // ST mode should ingore requested thread number.
++ ASSERT_NO_THROW_LOG(createMgr(3, 1, 1000));
++ ASSERT_TRUE(mgr_);
++
++ // Install a post reply received callback to stop the test if we're done.
++ int num_targets = 25;
++ mgr_->post_reply_received_cb_ =
++ [this, num_targets](const ICMPMsgPtr& /* reply */) {
++ MultiThreadingLock lock(*mutex_);
++ if (unparked_ == num_targets) {
++ stopTestService();
++ return;
++ }
++ };
++
++ // Start the manager. This will open the channel.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++ ASSERT_TRUE(mgr_->isRunning());
++
++ // Start the ping checks.
++ startTargets(num_targets);
++
++ // Run the main thread's IOService until we complete or timeout.
++ ASSERT_NO_THROW_LOG(runIOService());
++
++ // Stop the thread pool.
++ ASSERT_NO_THROW_LOG(mgr_->stop());
++ ASSERT_TRUE(mgr_->isStopped());
++
++ // Calling nextToSend() should return false.
++ IOAddress next("0.0.0.0");
++ ASSERT_FALSE(mgr_->nextToSend(next));
++
++ // We should have as many declines as we have pairs created.
++ compareLeaseQueryPairs(declines_);
++ }
++
++ /// @brief Generates a large number of ping checks to local loop back addresses.
++ ///
++ /// A pause is induced approximately halfway through the number of replies
++ /// at which point the manager is paused and then resumed. This is intended
++ /// to demonstrate the ability to pause and resume the manager gracefully.
++ /// The pings should all result in ECHO_REPLYs that get "declined". Declined
++ /// addresses are added to a list. Test completion is gated by the parking
++ /// lot becoming empty or test times out.
++ void testMultiplePingsWithReplyAndPause() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 1,
++ // reply_timeout 1000 milliseconds. Larger time out for this test
++ // avoids sporadic expirations which leads to unaccounted for UNPARKs.
++ // ST mode should ingore requested thread number.
++ ASSERT_NO_THROW_LOG(createMgr(3, 1, 1000));
++ ASSERT_TRUE(mgr_);
++
++ // Generate ping checks to the desired number of targets.
++ // Set up the pause callback to pause at half the number of
++ // expected replies.
++ size_t num_targets = 24;
++ size_t reply_cnt = 0;
++ size_t pause_at = num_targets / 2;
++ bool test_paused = false;
++
++ // Install post reply callback to stop the test thread when we reach
++ // the pause count.
++ mgr_->post_reply_received_cb_ =
++ [this, &reply_cnt, &test_paused, &pause_at](const ICMPMsgPtr& reply) {
++ MultiThreadingLock lock(*mutex_);
++ if (reply->getType() == ICMPMsg::ECHO_REPLY) {
++ ++reply_cnt;
++ if (pause_at && (reply_cnt >= pause_at)) {
++ test_paused = true;
++ stopTestService();
++ pause_at = 0;
++ }
++ }
++ };
++
++ // Start the manager. This will open the channel.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++ ASSERT_TRUE(mgr_->isRunning());
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++
++ // Start 1/2 desired number of ping checks.
++ startTargets(num_targets / 2);
++
++ // Run the main thread's IOService until we pause or timeout.
++ ASSERT_NO_THROW_LOG(mgr_->resume());
++ ASSERT_TRUE(mgr_->isRunning());
++ ASSERT_NO_THROW_LOG(runIOService());
++
++ // Manager should still be running. Pause it.
++ ASSERT_TRUE(mgr_->isRunning());
++ if (mgr_->getThreadPool()) {
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++ ASSERT_TRUE(mgr_->isPaused());
++ }
++
++ // Verify that the pause callback is why we stopped, that we
++ // received at least as many as we should have before pause
++ // and that we have more work to do. The test is a range as
++ // pausing does not happen exactly at the same point from test
++ // run to test run.
++ ASSERT_TRUE(test_paused);
++ ASSERT_TRUE((reply_cnt >= pause_at) && (reply_cnt < num_targets))
++ << "reply_cnt " << reply_cnt
++ << ", pause_at " << pause_at
++ << ", num_targets " << num_targets;
++
++ mgr_->post_reply_received_cb_ =
++ [this, num_targets](const ICMPMsgPtr& /* reply */) {
++ MultiThreadingLock lock(*mutex_);
++ if (unparked_ == num_targets) {
++ stopTestService();
++ return;
++ }
++ };
++
++ // Start second batch of targets.
++ startTargets(num_targets / 2, IOAddress("127.0.0.15"));
++
++ ASSERT_NO_THROW_LOG(mgr_->resume());
++ ASSERT_TRUE(mgr_->isRunning());
++
++ // Restart the main thread's IOService until we complete or timeout.
++ ASSERT_NO_THROW_LOG(runIOService());
++
++ ASSERT_NO_THROW_LOG(mgr_->stop());
++ ASSERT_TRUE(mgr_->isStopped());
++
++ // Calling nextToSend() should return false.
++ IOAddress next("0.0.0.0");
++ ASSERT_FALSE(mgr_->nextToSend(next));
++
++ // We should have as many declines as we have pairs created.
++ compareLeaseQueryPairs(declines_);
++ }
++
++ /// @brief Verifies that a recoverable error completion in sendCompleted() results
++ /// in the target address being free to use. In other words, it should have
++ /// the same outcome as the receiving a TARGET_UNREACHABLE reply from the OS.
++ void testSendCompletedSendFailed() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 1,
++ // reply_timeout 250 milliseconds.
++ // ST mode should ingore requested thread number.
++ ASSERT_NO_THROW_LOG(createMgr(3, 1, 250));
++ ASSERT_TRUE(mgr_);
++
++ // Install a post send completed callback to stop the test if we're done.
++ mgr_->post_send_completed_cb_ =
++ [this](const ICMPMsgPtr& /* echo */, bool send_failed) {
++ MultiThreadingLock lock(*mutex_);
++ if (send_failed) {
++ stopTestService();
++ }
++ };
++
++ // Start the manager.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++
++ // Set the test channel to complete the first send with a network_unreachable
++ // error. This saves us from trying to determine an address in the test
++ // environment that would cause it.
++ mgr_->getChannel()->ec_on_write_number_ = 1;
++ mgr_->getChannel()->write_error_ec_ = make_error_code(network_unreachable);
++
++ // Start a ping for one target.
++ startTargets(1);
++ auto lqp = lease_query_pairs_[0];
++
++ // Run the main thread's IOService until we complete or timeout.
++ ASSERT_NO_THROW_LOG(runIOService());
++
++ // Verify the expiration timer is no longer running.
++ EXPECT_EQ(mgr_->getExpirationTimerInterval(), 0);
++
++ // The context should no longer be in the store.
++ EXPECT_FALSE(getContext(lqp));
++
++ // We should have unparked the query from the lot.
++ EXPECT_EQ(mgr_->parkingLotSize(), 0);
++ EXPECT_EQ(unparked_, 1);
++
++ // We should have one free that matches our lease query pair.
++ compareLeaseQueryPairs(frees_);
++ }
++
++ /// @brief Exercises shouldPing().
++ void testShouldPingTest() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 1,
++ // reply_timeout 250 milliseconds.
++ // ST mode should ingore requested thread number.
++ ASSERT_NO_THROW_LOG(createMgr(3, 1, 250));
++ ASSERT_TRUE(mgr_);
++
++ // Make a default config.
++ PingCheckConfigPtr config(new PingCheckConfig());
++
++ // Make a lease query pair.
++ auto lqp1 = makeLeaseQueryPair(IOAddress("127.0.0.2"), 111);
++ const uint8_t id1[] = { 0x31, 0x32, 0x33, 0x34 };
++ ClientIdPtr cid1(new ClientId(id1, sizeof(id1)));
++ lqp1.lease_->client_id_ = cid1;
++
++ Lease4Ptr empty_lease;
++ CalloutHandle::CalloutNextStep status;
++
++ // Ping checking enabled, no old lease, channel doesn't exist, should return CONTINUE.
++ ASSERT_TRUE(config->getEnablePingCheck());
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, empty_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_CONTINUE);
++
++ // Start the manager, then pause it. This lets us start pings without
++ // them changing state.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++
++ // Ping checking disabled, no old lease, should return CONTINUE.
++ config->setEnablePingCheck(false);
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, empty_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_CONTINUE);
++
++ // Ping checking enabled, no old lease, should return PARK.
++ config->setEnablePingCheck(true);
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, empty_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_PARK);
++
++ // Make an old lease based on the first lease.
++ time_t now = time(0);
++ Lease4Ptr old_lease(new Lease4(*(lqp1.lease_)));
++
++ // Prior lease belonging to the same client with cltt greater than ping-cltt-secs
++ // should return PARK.
++ old_lease->cltt_ = now - config->getPingClttSecs() * 2;
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, old_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_PARK);
++
++ // Prior lease belonging to the same client but with cltt less than ping-cltt-secs
++ // should return CONTINUE.
++ old_lease->cltt_ = now - config->getPingClttSecs() / 2;
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, old_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_CONTINUE);
++
++ // Prior lease belonging to a different client, should return PARK.
++ const uint8_t id2[] = { 0x35, 0x36, 0x37, 0x34 };
++ old_lease->client_id_.reset(new ClientId(id2, sizeof(id2)));
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, old_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_PARK);
++
++ // Now let's start a ping for the lease-query pair.
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp1.lease_, lqp1.query_, parking_lot_));
++
++ // Make a second lease query pair. Same address, different client.
++ auto lqp2 = makeLeaseQueryPair(IOAddress("127.0.0.2"), 333);
++ lqp2.lease_->client_id_ = old_lease->client_id_;
++
++ // Trying to start a ping for an address already being checked should return DROP.
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp2.lease_, lqp2.query_, empty_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_DROP);
++
++ // Stop the mgr.
++ ASSERT_NO_THROW(mgr_->stop());
++
++ // Ping checking enabled, no old lease, channel isn't open, should return CONTINUE.
++ ASSERT_TRUE(config->getEnablePingCheck());
++ ASSERT_NO_THROW_LOG(status = mgr_->shouldPing(lqp1.lease_, lqp1.query_, empty_lease, config));
++ EXPECT_EQ(status, CalloutHandle::NEXT_STEP_CONTINUE);
++ }
++
++ /// @brief Exercise's getScopedConfig().
++ void testGetScopedConfig() {
++ CfgMgr::instance().setFamily(AF_INET);
++
++ // Start with empty cache, any subnet that hasn't been seen should get parsed
++ // and, if valid, added to the cache.
++ CfgMgr& cfg_mgr = CfgMgr::instance();
++ CfgSubnets4Ptr subnets = cfg_mgr.getStagingCfg()->getCfgSubnets4();
++
++ // Subnet 1 has no ping-check config. Should return global config.
++ ElementPtr user_context = Element::createMap();
++ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.1.0"), 24, 30, 40, 60, 1));
++ subnet->setContext(user_context);
++ subnets->add(subnet);
++
++ // Subnet 2 has invalid ping-check content. Should return global config.
++ std::string invalid_json_cfg =
++ R"({
++ "ping-check": {
++ "enable-ping-check" : true,
++ "bogus-key-word" : true
++ }
++ })";
++
++ user_context = Element::fromJSON(invalid_json_cfg);
++ subnet.reset(new Subnet4(IOAddress("192.0.2.0"), 24, 30, 40, 60, 2));
++ subnet->setContext(user_context);
++ subnets->add(subnet);
++
++ // Subnet 3 has valid ping check. Should return subnet config
++ std::string valid_json_cfg =
++ R"({
++ "ping-check": {
++ "enable-ping-check" : true,
++ "min-ping-requests" : 13
++ }
++ })";
++
++ user_context = Element::fromJSON(valid_json_cfg);
++ subnet.reset(new Subnet4(IOAddress("192.0.3.0"), 24, 30, 40, 60, 3));
++ subnet->setContext(user_context);
++ subnets->add(subnet);
++
++ // Commit the subnet configuration.
++ cfg_mgr.commit();
++
++ // Create manager with thread-pool size of 3, min_echos 2, reply_timeout 250 ms.
++ ASSERT_NO_THROW_LOG(createMgr(3, 2, 250));
++ ASSERT_TRUE(mgr_);
++
++ Lease4Ptr lease(new Lease4());
++ PingCheckConfigPtr config;
++
++ // Should get the global configuration for subnet 1.
++ lease->addr_ = IOAddress("192.0.1.1");
++ lease->subnet_id_ = 1;
++ ASSERT_NO_THROW_LOG(config = mgr_->getScopedConfig(lease));
++ ASSERT_TRUE(config);
++ ASSERT_EQ(config, mgr_->getGlobalConfig());
++
++ // Should get the global configuration for subnet 2.
++ lease->addr_ = IOAddress("192.0.2.1");
++ lease->subnet_id_ = 2;
++ ASSERT_NO_THROW_LOG(config = mgr_->getScopedConfig(lease));
++ ASSERT_TRUE(config);
++ ASSERT_EQ(config, mgr_->getGlobalConfig());
++
++ // Should get subnet configuration for subnet 3.
++ lease->addr_ = IOAddress("192.0.3.1");
++ lease->subnet_id_ = 3;
++ ASSERT_NO_THROW_LOG(config = mgr_->getScopedConfig(lease));
++ ASSERT_TRUE(config);
++ ASSERT_NE(config, mgr_->getGlobalConfig());
++ EXPECT_EQ(config->getMinPingRequests(), 13);
++ }
++
++ /// @brief Exercises checkSuspended().
++ ///
++ /// This is intended to verify that ping checking is suspended and resumed based
++ /// on the DHCP service state, not to verify every place that checkSuspended()
++ /// is called.
++ void testCheckSuspended() {
++ SKIP_IF(notRoot());
++
++ // Create manager with thread-pool size of 3, min_echos 1,
++ // reply_timeout 250 milliseconds.
++ ASSERT_NO_THROW_LOG(createMgr(3, 1, 250));
++ ASSERT_TRUE(mgr_);
++
++ // Make a default config.
++ PingCheckConfigPtr config(new PingCheckConfig());
++
++ // Give the manager a NetworkState instance.
++ NetworkStatePtr network_state(new NetworkState());
++ mgr_->setNetworkState(network_state);
++
++ // Verify that ping checking is not suspended.
++ ASSERT_FALSE(mgr_->checkSuspended());
++
++ // Start the manager, then pause it. This lets us start pings without
++ // them changing state.
++ ASSERT_NO_THROW_LOG(mgr_->start());
++ ASSERT_NO_THROW_LOG(mgr_->pause());
++
++ // Verfify the ping store is empty.
++ auto store = mgr_->getStore();
++ ASSERT_TRUE(store);
++ auto pings = store->getAll();
++ ASSERT_EQ(0, pings->size());
++
++ // Make a lease query pair.
++ auto lqp1 = makeLeaseQueryPair(IOAddress("127.0.0.2"), 111);
++ const uint8_t id1[] = { 0x31, 0x32, 0x33, 0x34 };
++ ClientIdPtr cid1(new ClientId(id1, sizeof(id1)));
++ lqp1.lease_->client_id_ = cid1;
++
++ // Now let's try to start a ping for the lease-query pair. It should work.
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp1.lease_, lqp1.query_, parking_lot_));
++
++ // Verify we have an entry in the store.
++ pings = store->getAll();
++ ASSERT_EQ(1, pings->size());
++
++ // Disable the DHCP service.
++ network_state->disableService(NetworkState::USER_COMMAND);
++
++ // Make a second lease query pair. Different address, different client.
++ auto lqp2 = makeLeaseQueryPair(IOAddress("127.0.0.3"), 333);
++ const uint8_t id2[] = { 0x31, 0x32, 0x33, 0x35 };
++ ClientIdPtr cid2(new ClientId(id1, sizeof(id2)));
++ lqp2.lease_->client_id_ = cid2;
++
++ // Try to start a ping. We should not be able to do it.
++ ASSERT_THROW_MSG(mgr_->startPing(lqp2.lease_, lqp2.query_, parking_lot_),
++ InvalidOperation,
++ "PingCheckMgr::startPing() - DHCP service is suspended!");
++
++ // Store should be empty, having been flushed by suspension detection.
++ pings = store->getAll();
++ ASSERT_EQ(0, pings->size());
++
++ // Ping checking should report as suspended.
++ ASSERT_TRUE(mgr_->checkSuspended());
++
++ // Re-enable the DHCP service.
++ network_state->enableService(NetworkState::USER_COMMAND);
++
++ // Suspension checking should lift the suspension and we should once again
++ // be able to start a new ping check.
++ ASSERT_NO_THROW_LOG(mgr_->startPing(lqp2.lease_, lqp2.query_, parking_lot_));
++
++ // Store should have one check in it.
++ pings = store->getAll();
++ ASSERT_EQ(1, pings->size());
++
++ // Ping checking should report as not suspended.
++ ASSERT_FALSE(mgr_->checkSuspended());
++ }
++
++ /// @brief Manager instance.
++ TestablePingCheckMgrPtr mgr_;
++
++ /// @brief List of lease/query pairs used during the test, in the order
++ /// they were created.
++ LeaseQueryPairs lease_query_pairs_;
++
++ /// @brief The mutex used to protect internal state.
++ const boost::scoped_ptr<std::mutex> mutex_;
++
++ /// @brief Marks the start time of a test.
++ TimeStamp test_start_time_;
++
++ /// @brief Parking lot where the associated query is parked.
++ /// If empty parking is not being employed.
++ ParkingLotHandlePtr parking_lot_;
++
++ /// @brief Number of queries unparked during a test.
++ size_t unparked_;
++
++ /// @brief List of leases that were found to be in-use during a test.
++ LeaseQueryPairs declines_;
++
++ /// @brief List of leases that were found to be free to use during a test.
++ LeaseQueryPairs frees_;
++};
++
++TEST_F(PingCheckMgrTest, operationalBasicsST) {
++ testOperationalBasics(0);
++}
++
++TEST_F(PingCheckMgrTest, operationalBasicsMT) {
++ MultiThreadingTest mt;
++ testOperationalBasics(3);
++}
++
++TEST_F(PingCheckMgrTest, startPingST) {
++ testStartPing();
++}
++
++TEST_F(PingCheckMgrTest, startPingMT) {
++ MultiThreadingTest mt;
++ testStartPing();
++}
++
++TEST_F(PingCheckMgrTest, nextToSendST) {
++ testNextToSend();
++}
++
++TEST_F(PingCheckMgrTest, nextToSendMT) {
++ MultiThreadingTest mt;
++ testNextToSend();
++}
++
++TEST_F(PingCheckMgrTest, setNextExpirationST) {
++ testSetNextExpiration();
++}
++
++TEST_F(PingCheckMgrTest, setNextExpirationMT) {
++ MultiThreadingTest mt;
++ testSetNextExpiration();
++}
++
++TEST_F(PingCheckMgrTest, sendCompletedST) {
++ testSendCompleted();
++}
++
++TEST_F(PingCheckMgrTest, sendCompletedMT) {
++ MultiThreadingTest mt;
++ testSendCompleted();
++}
++
++TEST_F(PingCheckMgrTest, replyReceivedForEchoReplyST) {
++ testReplyReceivedForEchoReply();
++}
++
++TEST_F(PingCheckMgrTest, replyReceivedForEchoReplyMT) {
++ MultiThreadingTest mt;
++ testReplyReceivedForEchoReply();
++}
++
++TEST_F(PingCheckMgrTest, replyReceivedForTargetUnreachableST) {
++ testReplyReceivedForTargetUnreachable();
++}
++
++TEST_F(PingCheckMgrTest, replyReceivedForTargetUnreachableMT) {
++ MultiThreadingTest mt;
++ testReplyReceivedForTargetUnreachable();
++}
++
++TEST_F(PingCheckMgrTest, expirationProcessingST) {
++ testExpirationProcessing();
++}
++
++TEST_F(PingCheckMgrTest, expirationProcessingMT) {
++ MultiThreadingTest mt;
++ testExpirationProcessing();
++}
++
++TEST_F(PingCheckMgrTest, multiplePingsWithReplyST) {
++ testMultiplePingsWithReply();
++}
++
++TEST_F(PingCheckMgrTest, multiplePingsWithReplyMT) {
++ MultiThreadingTest mt;
++ testMultiplePingsWithReply();
++}
++
++TEST_F(PingCheckMgrTest, multiplePingsWithReplyAndPauseST) {
++ testMultiplePingsWithReplyAndPause();
++}
++
++TEST_F(PingCheckMgrTest, multiplePingsWithReplyAndPauseMT) {
++ MultiThreadingTest mt;
++ testMultiplePingsWithReplyAndPause();
++}
++
++TEST_F(PingCheckMgrTest, sendCompletedSendFailedST) {
++ testSendCompletedSendFailed();
++}
++
++TEST_F(PingCheckMgrTest, sendCompletedSendFailedMT) {
++ MultiThreadingTest mt;
++ testSendCompletedSendFailed();
++}
++
++TEST_F(PingCheckMgrTest, shouldPingST) {
++ testShouldPingTest();
++}
++
++TEST_F(PingCheckMgrTest, shouldPingMT) {
++ MultiThreadingTest mt;
++ testShouldPingTest();
++}
++
++TEST_F(PingCheckMgrTest, getScopedConfigST) {
++ testGetScopedConfig();
++}
++
++TEST_F(PingCheckMgrTest, getScopedConfigMT) {
++ MultiThreadingTest mt;
++ testGetScopedConfig();
++}
++
++TEST_F(PingCheckMgrTest, checkSuspendedST) {
++ testCheckSuspended();
++}
++
++TEST_F(PingCheckMgrTest, checkSuspendedMT) {
++ MultiThreadingTest mt;
++ testCheckSuspended();
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_context_store_unittests.cc b/src/hooks/dhcp/ping_check/tests/ping_context_store_unittests.cc
+new file mode 100644
+index 0000000000..3a8854eb0e
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_context_store_unittests.cc
+@@ -0,0 +1,467 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the PingContextStore class.
++
++#include <config.h>
++#include <ping_context_store.h>
++#include <asiolink/io_address.h>
++#include <testutils/gtest_utils.h>
++#include <testutils/multi_threading_utils.h>
++
++#include <gtest/gtest.h>
++#include <sstream>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::ping_check;
++using namespace isc::test;
++using namespace std::chrono;
++
++namespace {
++
++/// @brief Text fixture class for @c PingContextStore
++///
++/// In order to facilitate single and multi threaded testing,
++/// individual tests are implemented as methods that are called
++/// from within TEST_F bodies rather than in TEST_F bodies.
++class PingContextStoreTest : public ::testing::Test {
++public:
++
++ /// @brief Constructor
++ PingContextStoreTest() {
++ }
++
++ /// @brief Destructor
++ virtual ~PingContextStoreTest() = default;
++
++ /// @brief Verifies that contexts can be added to the store given valid leases and queries.
++ /// Also verifies that they can be fetched by address.
++ void addContextTest() {
++ PingContextStore store;
++ PingContextPtr context;
++
++ // Add three contexts, one for each lease/query.
++ auto now = PingContext::now();
++ for (int i = 0; i < leases_.size(); ++i) {
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 2, 300));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++
++ // Check initial values.
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++ EXPECT_LE(now, context->getSendWaitStart());
++ EXPECT_EQ(2, context->getMinEchos());
++ EXPECT_EQ(300, context->getReplyTimeout());
++ }
++
++ // Make sure they can be fetched by address and by query individually.
++ for (int i = 0; i < leases_.size(); ++i) {
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[i]->addr_));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++
++ ASSERT_NO_THROW_LOG(context = store.getContextByQuery(queries_[i]));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(queries_[i], context->getQuery());
++ }
++ }
++
++ /// @brief Verifies that the store only allows once entry per IP address.
++ void addContextDuplicateTest() {
++ PingContextStore store;
++ PingContextPtr context;
++
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[0], queries_[0], 1, 100));
++ ASSERT_TRUE(context);
++ ASSERT_THROW_MSG(store.addContext(leases_[0], queries_[0], 1, 100), DuplicateContext,
++ "PingContextStore::addContex: context already exists for: 192.0.2.1");
++ }
++
++ /// @brief Verify that addContext fails given invalid input.
++ void addContextInvalidTest() {
++ PingContextStore store;
++
++ // Verify that given an empty lease the add will fail.
++ Lease4Ptr empty_lease;
++ ASSERT_THROW_MSG(store.addContext(empty_lease, queries_[0], 1, 100), BadValue,
++ "PingContextStore::addContext failed:"
++ " PingContext ctor - lease cannot be empty");
++
++ // Verify that given an empty query the add will fail.
++ Pkt4Ptr empty_query;
++ ASSERT_THROW_MSG(store.addContext(leases_[0], empty_query, 1, 100), BadValue,
++ "PingContextStore::addContext failed:"
++ " PingContext ctor - query cannot be empty");
++ }
++
++ /// @brief Verify that contexts can be deleted from the store.
++ void deleteContextTest() {
++ PingContextStore store;
++
++ // Add contexts to store.
++ for (int i = 0; i < leases_.size(); ++i) {
++ PingContextPtr context;
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 1, 100));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ }
++
++ // Fetch the second context.
++ PingContextPtr orig_context;
++ ASSERT_NO_THROW_LOG(orig_context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_TRUE(orig_context);
++ EXPECT_EQ(leases_[1], orig_context->getLease());
++
++ // Delete it.
++ ASSERT_NO_THROW_LOG(store.deleteContext(orig_context));
++
++ // Try to fetch it, shouldn't find it.
++ PingContextPtr context;
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_FALSE(context);
++
++ // Deleting it again should do no harm.
++ ASSERT_NO_THROW_LOG(store.deleteContext(orig_context));
++ }
++
++ /// @brief Verify that contexts in the store can be updated.
++ void updateContextTest() {
++ PingContextStore store;
++ PingContextPtr context;
++
++ // Try to update a context that doesn't exist. It should throw.
++ ASSERT_NO_THROW_LOG(context.reset(new PingContext(leases_[0], queries_[0])));
++ ASSERT_THROW_MSG(store.updateContext(context), InvalidOperation,
++ "PingContextStore::updateContext failed for address:"
++ " 192.0.2.1, not in store");
++
++ auto test_start = PingContext::now();
++
++ // Add contexts to store.
++ for (int i = 0; i < leases_.size(); ++i) {
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 1, 100));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ }
++
++ // Fetch the second context.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_TRUE(context);
++ ASSERT_EQ(leases_[1], context->getLease());
++ ASSERT_EQ(queries_[1], context->getQuery());
++
++ // Check initial values for state and expiration.
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++ EXPECT_LE(test_start, context->getSendWaitStart());
++ EXPECT_LE(PingContext::EMPTY_TIME(), context->getNextExpiry());
++
++ // Modify the state and expiration, then update the context.
++ auto wait_start = PingContext::now();
++ context->beginWaitingForReply(wait_start);
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Fetch the context and verify the values are correct.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(PingContext::WAITING_FOR_REPLY, context->getState());
++ EXPECT_LE(wait_start + milliseconds(context->getReplyTimeout()), context->getNextExpiry());
++ }
++
++ /// @brief Verify that contexts can be fetched based on when they entered WAITING_TO_SEND
++ /// by getNextToSend().
++ void getNextToSendTest() {
++ PingContextStore store;
++ PingContextPtr context;
++
++ // Capture time now.
++ auto start_time = PingContext::now();
++
++ // Add contexts to store.
++ for (int i = 0; i < leases_.size(); ++i) {
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 1, 100));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ usleep(1000);
++ }
++
++ // Fetching the next context to send should return the first context as
++ // it has the oldest send wait start time.
++ context.reset();
++ ASSERT_NO_THROW(context = store.getNextToSend());
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[0], context->getLease());
++ EXPECT_EQ(queries_[0], context->getQuery());
++ EXPECT_LE(start_time, context->getSendWaitStart());
++
++ // Update the first context's state to TARGET_FREE which should
++ // disqualify it from being returned as next to send.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[0]->addr_));
++ ASSERT_TRUE(context);
++ ASSERT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++ context->setState(PingContext::TARGET_FREE);
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Update the send wait start of the second context making it the
++ // youngest send wait start time.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_TRUE(context);
++ ASSERT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++ context->setSendWaitStart(start_time + milliseconds(1000));
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Update the send wait start of the third context, making it the oldest.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[2]->addr_));
++ ASSERT_TRUE(context);
++ ASSERT_EQ(PingContext::WAITING_TO_SEND, context->getState());
++ context->setSendWaitStart(start_time + milliseconds(500));
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Fetching the next context to send should return the third context.
++ context.reset();
++ ASSERT_NO_THROW(context = store.getNextToSend());
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[2], context->getLease());
++ EXPECT_EQ(queries_[2], context->getQuery());
++ EXPECT_EQ(start_time + milliseconds(500), context->getSendWaitStart());
++ }
++
++ /// @brief Verify that contexts can be fetched based on when they expire using
++ /// getExpiresNext() and getExpiredSince().
++ void getByExpirationTest() {
++ PingContextStore store;
++ PingContextPtr context;
++
++ // Add contexts to store.
++ for (int i = 0; i < leases_.size(); ++i) {
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 1, 100));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ }
++
++ // Capture time now.
++ auto start_time = PingContext::now();
++
++ // Update the state and expiration of the first context.
++ // State set to TARGET_FREE should disqualify if from
++ // fetch by expiration even though it has the soonest expiration
++ // time.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[0]->addr_));
++ ASSERT_TRUE(context);
++ context->setState(PingContext::TARGET_FREE);
++ context->setNextExpiry(start_time + milliseconds(1));
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Update the state and expiration of the second context giving it
++ // the youngest expiration time.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[1]->addr_));
++ ASSERT_TRUE(context);
++ context->setState(PingContext::WAITING_FOR_REPLY);
++ context->setNextExpiry(start_time + milliseconds(1000));
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Update the state and expiration of the third context, make it the
++ // soonest qualified expiration time.
++ ASSERT_NO_THROW_LOG(context = store.getContextByAddress(leases_[2]->addr_));
++ ASSERT_TRUE(context);
++ context->setState(PingContext::WAITING_FOR_REPLY);
++ context->setNextExpiry(start_time + milliseconds(500));
++ ASSERT_NO_THROW_LOG(store.updateContext(context));
++
++ // Fetching the context that expires next should return the third context.
++ context.reset();
++ ASSERT_NO_THROW(context = store.getExpiresNext());
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[2], context->getLease());
++ EXPECT_EQ(queries_[2], context->getQuery());
++ EXPECT_EQ(start_time + milliseconds(500), context->getNextExpiry());
++
++ // Fetch all that have expired since current time. Should be none.
++ PingContextCollectionPtr expired_since;
++ ASSERT_NO_THROW_LOG(expired_since = store.getExpiredSince());
++ ASSERT_TRUE(expired_since);
++ EXPECT_EQ(0, expired_since->size());
++
++ // Fetch all that have expired since start time + 750 ms, should be third context.
++ ASSERT_NO_THROW_LOG(expired_since = store.getExpiredSince(start_time + milliseconds(750)));
++ ASSERT_TRUE(expired_since);
++ EXPECT_EQ(1, expired_since->size());
++ context = (*expired_since)[0];
++ EXPECT_EQ(leases_[2], context->getLease());
++ EXPECT_EQ(queries_[2], context->getQuery());
++ EXPECT_EQ(start_time + milliseconds(500), context->getNextExpiry());
++
++ // Fetch all that have expired since start time + 1500 ms
++ // Should be the third and second contexts
++ ASSERT_NO_THROW_LOG(expired_since = store.getExpiredSince(start_time + milliseconds(1500)));
++ ASSERT_TRUE(expired_since);
++ EXPECT_EQ(2, expired_since->size());
++
++ // First in list should be the third context.
++ context = (*expired_since)[0];
++ EXPECT_EQ(leases_[2], context->getLease());
++ EXPECT_EQ(queries_[2], context->getQuery());
++ EXPECT_EQ(start_time + milliseconds(500), context->getNextExpiry());
++
++ // The last one in the list should be the second context.
++ context = (*expired_since)[1];
++ EXPECT_EQ(leases_[1], context->getLease());
++ EXPECT_EQ(queries_[1], context->getQuery());
++ EXPECT_EQ(start_time + milliseconds(1000), context->getNextExpiry());
++ }
++
++ /// @brief Verifies that getAll() and clear() work properly.
++ void getAllAndClearTest() {
++ PingContextStore store;
++
++ // Add contexts to store.
++ for (int i = 0; i < leases_.size(); ++i) {
++ PingContextPtr context;
++ ASSERT_NO_THROW_LOG(context = store.addContext(leases_[i], queries_[i], 1, 100));
++ ASSERT_TRUE(context);
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ }
++
++ // Fetch them all.
++ PingContextCollectionPtr contexts;
++ ASSERT_NO_THROW_LOG(contexts = store.getAll());
++ ASSERT_EQ(leases_.size(), contexts->size());
++
++ // Verify we got them all in order.
++ int i = 0;
++ for (auto const& context : *contexts) {
++ EXPECT_EQ(leases_[i], context->getLease());
++ EXPECT_EQ(queries_[i], context->getQuery());
++ ++i;
++ }
++
++ // Now clear the store. Verify it's empty.
++ ASSERT_NO_THROW_LOG(store.clear());
++ ASSERT_NO_THROW_LOG(contexts = store.getAll());
++ ASSERT_EQ(0, contexts->size());
++
++ // Verify clearing an empty store does no harm.
++ ASSERT_NO_THROW_LOG(store.clear());
++ }
++
++private:
++ /// @brief Prepares the class for a test.
++ virtual void SetUp() {
++ Lease4Ptr lease;
++ lease.reset(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.1");
++ leases_.push_back(lease);
++
++ lease.reset(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.2");
++ leases_.push_back(lease);
++
++ lease.reset(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.3");
++ leases_.push_back(lease);
++
++ Pkt4Ptr query;
++ query.reset(new Pkt4(DHCPDISCOVER, 101));
++ queries_.push_back(query);
++
++ query.reset(new Pkt4(DHCPDISCOVER, 102));
++ queries_.push_back(query);
++
++ query.reset(new Pkt4(DHCPDISCOVER, 103));
++ queries_.push_back(query);
++
++ ASSERT_EQ(leases_.size(), queries_.size());
++ }
++
++public:
++ /// @brief List of pre-made leases.
++ std::vector<Lease4Ptr> leases_;
++
++ /// @brief List of pre-made queries.
++ std::vector<Pkt4Ptr> queries_;
++};
++
++TEST_F(PingContextStoreTest, addContext) {
++ addContextTest();
++}
++
++TEST_F(PingContextStoreTest, addContextMultiThreading) {
++ MultiThreadingTest mt;
++ addContextTest();
++}
++
++TEST_F(PingContextStoreTest, addContextDuplicate) {
++ addContextDuplicateTest();
++}
++
++TEST_F(PingContextStoreTest, addContextDuplicateMultiThreading) {
++ MultiThreadingTest mt;
++ addContextDuplicateTest();
++}
++
++TEST_F(PingContextStoreTest, addContextInvalid) {
++ addContextInvalidTest();
++}
++
++TEST_F(PingContextStoreTest, addContextInvalidMultiThreading) {
++ MultiThreadingTest mt;
++ addContextInvalidTest();
++}
++
++TEST_F(PingContextStoreTest, deleteContext) {
++ deleteContextTest();
++}
++
++TEST_F(PingContextStoreTest, deleteContextMultiThreading) {
++ MultiThreadingTest mt;
++ deleteContextTest();
++}
++
++TEST_F(PingContextStoreTest, updateContext) {
++ updateContextTest();
++}
++
++TEST_F(PingContextStoreTest, updateContextMultiThreading) {
++ MultiThreadingTest mt;
++ updateContextTest();
++}
++
++TEST_F(PingContextStoreTest, getNextToSend) {
++ getNextToSendTest();
++}
++
++TEST_F(PingContextStoreTest, getNextToSendMultiThreading) {
++ MultiThreadingTest mt;
++ getNextToSendTest();
++}
++
++TEST_F(PingContextStoreTest, getByExpiration) {
++ getByExpirationTest();
++}
++
++TEST_F(PingContextStoreTest, getByExpirationMultiThreading) {
++ MultiThreadingTest mt;
++ getByExpirationTest();
++}
++
++TEST_F(PingContextStoreTest, getAllAndClear) {
++ getAllAndClearTest();
++}
++
++TEST_F(PingContextStoreTest, getAllAndClearMultiThreading) {
++ MultiThreadingTest mt;
++ getAllAndClearTest();
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_context_unittests.cc b/src/hooks/dhcp/ping_check/tests/ping_context_unittests.cc
+new file mode 100644
+index 0000000000..4a38277ad6
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_context_unittests.cc
+@@ -0,0 +1,146 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++/// @file This file contains tests which exercise the PingContext class.
++
++#include <config.h>
++#include <ping_context.h>
++#include <asiolink/io_address.h>
++#include <testutils/gtest_utils.h>
++
++#include <gtest/gtest.h>
++#include <sstream>
++
++using namespace std;
++using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::dhcp;
++using namespace isc::ping_check;
++using namespace std::chrono;
++
++namespace {
++
++TEST(PingContextTest, validConstruction) {
++ // Make a valid lease and query.
++ Lease4Ptr lease(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.1");
++ Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
++
++ // Capture time now.
++ auto start_time = PingContext::now();
++
++ // Construct the context.
++ PingContextPtr context;
++ ASSERT_NO_THROW_LOG(context.reset(new PingContext(lease, query)));
++
++ // Verify initial content.
++ EXPECT_EQ(lease->addr_, context->getTarget());
++ EXPECT_EQ(1, context->getMinEchos());
++ EXPECT_EQ(100, context->getReplyTimeout());
++ EXPECT_EQ(0, context->getEchosSent());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getLastEchoSentTime());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getSendWaitStart());
++ EXPECT_EQ(PingContext::EMPTY_TIME(), context->getNextExpiry());
++ EXPECT_EQ(PingContext::NEW, context->getState());
++
++ // Start time should be less than or equal to created time.
++ EXPECT_LE(start_time, context->getCreatedTime());
++ EXPECT_EQ(lease, context->getLease());
++ EXPECT_EQ(query, context->getQuery());
++}
++
++TEST(PingContextTest, invalidConstruction) {
++ // Make a valid lease and query.
++ Lease4Ptr lease(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.1");
++ Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
++
++ // Empty lease should throw.
++ Lease4Ptr empty_lease;
++ PingContextPtr context;
++ ASSERT_THROW_MSG(context.reset(new PingContext(empty_lease, query)), BadValue,
++ "PingContext ctor - lease cannot be empty");
++
++ // Empty query should throw.
++ Pkt4Ptr empty_query;
++ ASSERT_THROW_MSG(context.reset(new PingContext(lease, empty_query)), BadValue,
++ "PingContext ctor - query cannot be empty");
++
++ // Empty lease address should throw.
++ lease->addr_ = IOAddress::IPV4_ZERO_ADDRESS();
++ ASSERT_THROW_MSG(context.reset(new PingContext(lease, query)), BadValue,
++ "PingContext ctor - target address cannot be 0.0.0.0");
++}
++
++// Tests conversion of PingContext::State to string and vice-versa.
++TEST(PingContext, stateConversion) {
++ EXPECT_EQ(PingContext::NEW, PingContext::stringToState("NEW"));
++ EXPECT_EQ(PingContext::WAITING_TO_SEND, PingContext::stringToState("WAITING_TO_SEND"));
++ EXPECT_EQ(PingContext::SENDING, PingContext::stringToState("SENDING"));
++ EXPECT_EQ(PingContext::WAITING_FOR_REPLY, PingContext::stringToState("WAITING_FOR_REPLY"));
++ EXPECT_EQ(PingContext::TARGET_FREE, PingContext::stringToState("TARGET_FREE"));
++ EXPECT_EQ(PingContext::TARGET_IN_USE, PingContext::stringToState("TARGET_IN_USE"));
++ ASSERT_THROW_MSG(PingContext::stringToState("bogus"), BadValue,
++ "Invalid PingContext::State: 'bogus'");
++
++ EXPECT_EQ("NEW", PingContext::stateToString(PingContext::NEW));
++ EXPECT_EQ("WAITING_TO_SEND", PingContext::stateToString(PingContext::WAITING_TO_SEND));
++ EXPECT_EQ("SENDING", PingContext::stateToString(PingContext::SENDING));
++ EXPECT_EQ("WAITING_FOR_REPLY", PingContext::stateToString(PingContext::WAITING_FOR_REPLY));
++ EXPECT_EQ("TARGET_FREE", PingContext::stateToString(PingContext::TARGET_FREE));
++ EXPECT_EQ("TARGET_IN_USE", PingContext::stateToString(PingContext::TARGET_IN_USE));
++}
++
++TEST(PingContext, accessors) {
++ // Make a valid lease and query.
++ Lease4Ptr lease(new Lease4());
++ lease->addr_ = IOAddress("192.0.2.1");
++ Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
++
++ // Capture time now.
++ auto time_now = PingContext::now();
++
++ // Construct a context.
++ PingContextPtr context;
++ ASSERT_NO_THROW_LOG(context.reset(new PingContext(lease, query, 1, 50)));
++
++ EXPECT_NO_THROW_LOG(context->setMinEchos(4));
++ EXPECT_EQ(4, context->getMinEchos());
++
++ EXPECT_NO_THROW_LOG(context->setReplyTimeout(200));
++ EXPECT_EQ(200, context->getReplyTimeout());
++
++ EXPECT_NO_THROW_LOG(context->setEchosSent(7));
++ EXPECT_EQ(7, context->getEchosSent());
++
++ EXPECT_NO_THROW_LOG(context->setLastEchoSentTime(time_now));
++ EXPECT_EQ(time_now, context->getLastEchoSentTime());
++
++ EXPECT_NO_THROW_LOG(context->setState(PingContext::SENDING));
++ EXPECT_EQ(PingContext::SENDING, context->getState());
++
++ time_now += milliseconds(100);
++ EXPECT_NO_THROW_LOG(context->setSendWaitStart(time_now));
++ EXPECT_EQ(time_now, context->getSendWaitStart());
++
++ time_now += milliseconds(100);
++ EXPECT_NO_THROW_LOG(context->setNextExpiry(time_now));
++ EXPECT_EQ(time_now, context->getNextExpiry());
++
++ EXPECT_FALSE(context->isWaitingToSend());
++ time_now += milliseconds(100);
++ ASSERT_NO_THROW_LOG(context->beginWaitingToSend(time_now));
++ EXPECT_EQ(time_now, context->getSendWaitStart());
++ EXPECT_TRUE(context->isWaitingToSend());
++
++ EXPECT_FALSE(context->isWaitingForReply());
++ auto exp_expiry = time_now + milliseconds(context->getReplyTimeout());
++ ASSERT_NO_THROW_LOG(context->beginWaitingForReply(time_now));
++ EXPECT_EQ(exp_expiry, context->getNextExpiry());
++ EXPECT_TRUE(context->isWaitingForReply());
++}
++
++} // end of anonymous namespace
+diff --git a/src/hooks/dhcp/ping_check/tests/ping_test_utils.h b/src/hooks/dhcp/ping_check/tests/ping_test_utils.h
+new file mode 100644
+index 0000000000..df1ede7526
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/ping_test_utils.h
+@@ -0,0 +1,396 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#ifndef PING_TEST_UTILS_H
++#define PING_TEST_UTILS_H
++
++#include <ping_channel.h>
++#include <asiolink/interval_timer.h>
++#include <asiolink/io_service.h>
++#include <asiolink/io_address.h>
++#include <testutils/gtest_utils.h>
++#include <asiolink/io_service_thread_pool.h>
++#include <util/multi_threading_mgr.h>
++#include <mutex>
++
++#include <gtest/gtest.h>
++#include <queue>
++#include <list>
++#include <thread>
++#include <map>
++
++namespace isc {
++namespace ping_check {
++
++/// @brief Test timeout (ms).
++const long TEST_TIMEOUT = 10000;
++
++/// @brief Maps IOAddresses to sequence numbers.
++///
++/// Outbound requests are assigned a unique id and sequence
++/// number. This map is used to track the request's destination
++/// address by its sequence number. The channel can then substitute
++/// the loopback address, 127.0.0.1, as the destination address.
++/// Upon response receipt, the original destination can be found by
++/// the sequence number sent back in the response.
++class LoopbackMap {
++public:
++ /// @brief Constructor.
++ LoopbackMap() : map_(), mutex_(new std::mutex) {
++ }
++
++ /// @brief Destructor.
++ ~LoopbackMap() = default;
++
++ /// @brief Find and IOAddress associated with a sequence number.
++ ///
++ /// @param sequence sequence number to search by
++ ///
++ /// @return address found or IPV4_ZERO_ADDRESS.
++ asiolink::IOAddress find(uint16_t sequence) {
++ util::MultiThreadingLock lock(*mutex_);
++ auto const& iter = map_.find(sequence);
++ if (iter == map_.end()) {
++ return (asiolink::IOAddress::IPV4_ZERO_ADDRESS());
++ }
++
++ return (iter->second);
++ }
++
++ /// @brief Adds an entry for a sequence number and address
++ ///
++ /// @param sequence sequence number associated with the address
++ /// @param address address to add to the map
++ ///
++ /// @return true if the entry was added, false otherwise.
++ bool add(uint16_t sequence, const asiolink::IOAddress& address) {
++ util::MultiThreadingLock lock(*mutex_);
++ if (map_.count(sequence)) {
++ return (false);
++ }
++
++ map_.emplace(sequence, address);
++ return (true);
++ };
++
++ /// @brief Map of addresses by sequence number.
++ std::map<uint16_t, asiolink::IOAddress> map_;
++
++ /// @brief Mutex to protect the map during operations.
++ const boost::scoped_ptr<std::mutex> mutex_;
++};
++
++/// @brief Testable derivation of PingChannel
++///
++/// Overrides read and write functions to inject IO errors.
++class TestablePingChannel : public PingChannel {
++public:
++ /// @brief Constructor
++ ///
++ /// Instantiates the channel with its socket closed.
++ ///
++ /// @param io_service pointer to the IOService instance that will manage
++ /// the channel's IO. Must not be empty
++ /// @param next_to_send_cb callback to invoke to fetch the next IOAddress
++ /// to ping
++ /// @param echo_sent_cb callback to invoke when an ECHO send has completed
++ /// @param reply_received_cb callback to invoke when an ICMP reply has been
++ /// received. This callback is passed all inbound ICMP messages (e.g. ECHO
++ /// REPLY, UNREACHABLE, etc...)
++ /// @param shutdown_cb callback to invoke when the channel has shutdown due
++ /// to an error
++ ///
++ /// @throw BadValue if io_service is empty.
++ TestablePingChannel(asiolink::IOServicePtr& io_service,
++ NextToSendCallback next_to_send_cb,
++ EchoSentCallback echo_sent_cb,
++ ReplyReceivedCallback reply_received_cb,
++ ShutdownCallback shutdown_cb = ShutdownCallback())
++ : PingChannel(io_service, next_to_send_cb, echo_sent_cb, reply_received_cb, shutdown_cb),
++ read_number_(0), throw_on_read_number_(0), ec_on_read_number_(0), read_error_ec_(),
++ write_number_(0), throw_on_write_number_(0), ec_on_write_number_(0), write_error_ec_(),
++ route_loopback_(true), loopback_map_(), stopped_(false) {
++ }
++
++ /// @brief Virtual destructor
++ virtual ~TestablePingChannel() {
++ stopped_ = true;
++ }
++
++ // @brief Schedules the next send.
++ //
++ // If the socket is not currently sending it posts a call to @c sendNext()
++ // to the channel's IOService.
++ virtual void startSend() {
++ if (stopped_) {
++ return;
++ }
++ PingChannel::startSend();
++ }
++
++ /// @brief Perform asynchronous read or feign a read error
++ ///
++ /// This virtual function is provided as means to inject errors during
++ /// read operations to facilitate testing. It tracks the number of
++ /// reads that have occurred since channel open and instigates an
++ /// error trigger on the trigger read number if a trigger has been set.
++ ///
++ /// @param data buffer to receive incoming message
++ /// @param length length of the data buffer
++ /// @param offset offset into buffer where data is to be put
++ /// @param endpoint source of the communication
++ /// @param callback callback object
++ virtual void asyncReceive(void* data, size_t length, size_t offset,
++ asiolink::IOEndpoint* endpoint, SocketCallback& callback) {
++ if (stopped_) {
++ return;
++ }
++ ++read_number_;
++
++ // If we're set to fail with an exception, do so.
++ if (throw_on_read_number_ && (read_number_ == throw_on_read_number_)) {
++ isc_throw(Unexpected, "Injected read error");
++ }
++
++ // If we're set to fail via the callback, post a call with the
++ // desired error code.
++ if (ec_on_read_number_ && read_number_ == ec_on_read_number_) {
++ getIOService()->post([this]() { socketReadCallback(read_error_ec_, 0); });
++ return;
++ }
++
++ // No scheduled error, proceed with normal read.
++ PingChannel::asyncReceive(data, length, offset, endpoint, callback);
++ }
++
++ /// @brief Perform asynchronous write or feign a write error
++ ///
++ /// This virtual function is provided as means to inject errors during
++ /// write operations to facilitate testing. It tracks the number of
++ /// writes that have occurred since channel open and instigates an
++ /// error trigger on the trigger write number if a trigger has been set.
++ ///
++ /// @param data buffer of data to write
++ /// @param length length of the data buffer
++ /// @param endpoint destination of the communication
++ /// @param callback callback object
++ virtual void asyncSend(void* data, size_t length, asiolink::IOEndpoint* endpoint,
++ SocketCallback& callback) {
++ if (stopped_) {
++ return;
++ }
++ ++write_number_;
++ if (throw_on_write_number_ && (write_number_ == throw_on_write_number_)) {
++ isc_throw(Unexpected, "Injected write error");
++ }
++
++ if (ec_on_write_number_ && write_number_ == ec_on_write_number_) {
++ ICMPMsgPtr fake_echo(new ICMPMsg());
++ fake_echo->setType(ICMPMsg::ECHO_REQUEST);
++ fake_echo->setDestination(endpoint->getAddress());
++ getIOService()->post([this, fake_echo]() { socketWriteCallback(fake_echo, write_error_ec_, 0); });
++ return;
++ }
++
++ // In order to make testing more predictable, we need slow writes down a bit.
++ usleep(5000);
++
++ // If loopback routing is enabled, store the destination address by
++ // sequence number in the loopback map, then replace the destination
++ // endpoint with 127.0.0.1 and send it there.
++ if (route_loopback_) {
++ struct icmp* reply = (struct icmp*)(data);
++ auto sequence = (ntohs(reply->icmp_hun.ih_idseq.icd_seq));
++ loopback_map_.add(sequence, endpoint->getAddress());
++ ICMPEndpoint lo_endpoint(asiolink::IOAddress("127.0.0.1"));
++ PingChannel::asyncSend(data, length, &lo_endpoint, callback);
++ return;
++ }
++
++ PingChannel::asyncSend(data, length, endpoint, callback);
++ }
++
++ /// @brief Fetches the PingSocket.
++ ///
++ /// @return pointer to the PingSocket instance.
++ PingSocketPtr getPingSocket() {
++ return (socket_);
++ }
++
++ /// @brief Checks if channel was opened in single-threaded mode.
++ ///
++ /// @return True if channel is single-threaded.
++ bool getSingleThreaded() const {
++ return (single_threaded_);
++ }
++
++ /// @brief Fetch the WatchSocket instance.
++ ///
++ /// @return pointer to the WatchSocket.
++ util::WatchSocketPtr getWatchSocket() const {
++ return (watch_socket_);
++ }
++
++ /// @brief The "write-ready" socket descriptor registered IfaceMgr.
++ ///
++ /// @return registered socket descriptor.
++ int getRegisteredWriteFd() const {
++ return (registered_write_fd_);
++ }
++
++ /// @brief The "read-ready" socket descriptor registered IfaceMgr.
++ ///
++ /// @return registered socket descriptor.
++ int getRegisteredReadFd() const {
++ return (registered_read_fd_);
++ }
++
++ /// @brief Tracks the number of reads since the channel was created
++ size_t read_number_;
++
++ /// @brief Read number on which to thrown an exception from asyncReceive()
++ size_t throw_on_read_number_;
++
++ /// @brief Read number on which to inject a socketReadCallback with an error code
++ size_t ec_on_read_number_;
++
++ /// @brief Error code to inject on read error trigger
++ boost::system::error_code read_error_ec_;
++
++ /// @brief Tracks the number of writes since the channel was created
++ size_t write_number_;
++
++ /// @brief Write number on which to thrown an exception from asyncSend()
++ size_t throw_on_write_number_;
++
++ /// @brief Error code to inject on write error trigger
++ size_t ec_on_write_number_;
++
++ /// @brief Error code to inject on write error trigger
++ boost::system::error_code write_error_ec_;
++
++ /// @brief Enables routing of 127.0.0.x by to 127.0.0.1 via sequence number.
++ bool route_loopback_;
++
++ /// @brief Maps loopback addresses to sequence numbers when loopback routing
++ /// is enabled.
++ LoopbackMap loopback_map_;
++
++ /// @brief Flag which indicates that the manager has been stopped.
++ bool stopped_;
++};
++
++/// @brief Defines a pointer to a TestablePingChannel
++typedef boost::shared_ptr<TestablePingChannel> TestablePingChannelPtr;
++
++/// @brief Defines a callback type for test completion check functions.
++typedef std::function<bool()> TestDoneCallback;
++
++/// @brief Test fixture class which uses an IOService for time management and/or IO
++class IOServiceTest : public ::testing::Test {
++public:
++ /// @brief Constructor.
++ ///
++ /// Starts test timer which detects timeouts.
++ IOServiceTest()
++ : test_io_service_(new asiolink::IOService()),
++ test_timer_(test_io_service_),
++ run_io_service_timer_(test_io_service_),
++ test_done_cb_() {
++ test_timer_.setup(std::bind(&IOServiceTest::timeoutHandler, this, true),
++ TEST_TIMEOUT,
++ asiolink::IntervalTimer::ONE_SHOT);
++ }
++
++ /// @brief Indicates if current user is not root
++ ///
++ /// @return True if neither the uid or the effective
++ /// uid is root.
++ static bool notRoot() {
++ return (getuid() != 0 && geteuid() != 0);
++ }
++
++ /// @brief Destructor.
++ ///
++ /// Removes active clients.
++ virtual ~IOServiceTest() {
++ test_timer_.cancel();
++ run_io_service_timer_.cancel();
++ test_io_service_->stopAndPoll();
++ }
++
++ /// @brief Callback function invoke upon test timeout.
++ ///
++ /// It stops the IO service and reports test timeout.
++ ///
++ /// @param fail_on_timeout Specifies if test failure should be reported.
++ void timeoutHandler(const bool fail_on_timeout) {
++ if (fail_on_timeout) {
++ ADD_FAILURE() << "Timeout occurred while running the test!";
++ }
++
++ test_io_service_->stop();
++ }
++
++ /// @brief Stops the IOService if criteria for test completion has been met.
++ ///
++ /// Stops the IOService If there either no test completion callback or the
++ /// call back returns true.
++ void stopIfDone() {
++ // If there is no done test callback or it returns true, stop the service.
++ if (!test_done_cb_ || (test_done_cb_)()) {
++ test_io_service_->stop();
++ }
++ }
++
++ /// @brief Posts a call to stop the io service to the io service.
++ ///
++ /// This should be used when stopping the service from callbacks on
++ /// thread pool threads.
++ void stopTestService() {
++ if (!test_io_service_->stopped()) {
++ test_io_service_->post([&]() { test_io_service_->stop(); });
++ }
++ }
++
++ /// @brief Runs IO service with optional timeout.
++ ///
++ /// @param timeout number of milliseconds to run the io service. Defaults to
++ /// zero which means run forever.
++ void runIOService(long timeout = 0) {
++ test_io_service_->stop();
++ test_io_service_->restart();
++
++ if (timeout > 0) {
++ run_io_service_timer_.setup(std::bind(&IOServiceTest::timeoutHandler,
++ this, false),
++ timeout,
++ asiolink::IntervalTimer::ONE_SHOT);
++ }
++
++ test_io_service_->run();
++ test_io_service_->stopAndPoll();
++ }
++
++ /// @brief IO service used in the tests.
++ asiolink::IOServicePtr test_io_service_;
++
++ /// @brief Asynchronous timer service to detect timeouts.
++ asiolink::IntervalTimer test_timer_;
++
++ /// @brief Asynchronous timer for running IO service for a specified amount
++ /// of time.
++ asiolink::IntervalTimer run_io_service_timer_;
++
++ /// @brief Callback function which event handlers can use to check if service
++ /// run should stop.
++ TestDoneCallback test_done_cb_;
++};
++
++} // end of namespace ping_check
++} // end of namespace isc
++
++#endif
+diff --git a/src/hooks/dhcp/ping_check/tests/run_unittests.cc b/src/hooks/dhcp/ping_check/tests/run_unittests.cc
+new file mode 100644
+index 0000000000..d249e2362e
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/tests/run_unittests.cc
+@@ -0,0 +1,19 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++
++#include <log/logger_support.h>
++#include <gtest/gtest.h>
++
++int
++main(int argc, char* argv[]) {
++ ::testing::InitGoogleTest(&argc, argv);
++ isc::log::initLogger();
++ int result = RUN_ALL_TESTS();
++
++ return (result);
++}
+diff --git a/src/hooks/dhcp/ping_check/version.cc b/src/hooks/dhcp/ping_check/version.cc
+new file mode 100644
+index 0000000000..f2250ab126
+--- /dev/null
++++ b/src/hooks/dhcp/ping_check/version.cc
+@@ -0,0 +1,17 @@
++// Copyright (C) 2023-2025 Internet Systems Consortium, Inc. ("ISC")
++//
++// This Source Code Form is subject to the terms of the Mozilla Public
++// License, v. 2.0. If a copy of the MPL was not distributed with this
++// file, You can obtain one at http://mozilla.org/MPL/2.0/.
++
++#include <config.h>
++#include <hooks/hooks.h>
++
++extern "C" {
++
++/// @brief returns Kea hooks version.
++int version() {
++ return (KEA_HOOKS_VERSION);
++}
++
++}
+--
+2.39.5 (Apple Git-154)
+
diff --git a/scripts/package-build/keepalived/.gitignore b/scripts/package-build/keepalived/.gitignore
index fa96cd3f..b6513f29 100644
--- a/scripts/package-build/keepalived/.gitignore
+++ b/scripts/package-build/keepalived/.gitignore
@@ -1,7 +1 @@
-keepalived/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/keepalived/
diff --git a/scripts/package-build/keepalived/package.toml b/scripts/package-build/keepalived/package.toml
index ad1008e6..3f5ec071 100644
--- a/scripts/package-build/keepalived/package.toml
+++ b/scripts/package-build/keepalived/package.toml
@@ -1,4 +1,4 @@
[[packages]]
name = "keepalived"
-commit_id = "debian/1%2.2.8-1"
+commit_id = "debian/1%2.3.2-1"
scm_url = "https://salsa.debian.org/debian/pkg-keepalived.git"
diff --git a/scripts/package-build/keepalived/patches/0001-vrrp-Set-sysctl-arp_ignore-to-1-on-IPv6-VMACs.patch b/scripts/package-build/keepalived/patches/0001-vrrp-Set-sysctl-arp_ignore-to-1-on-IPv6-VMACs.patch
deleted file mode 100644
index b099dc7b..00000000
--- a/scripts/package-build/keepalived/patches/0001-vrrp-Set-sysctl-arp_ignore-to-1-on-IPv6-VMACs.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From af4aa758c3512bec8233549e138b03741c5404f9 Mon Sep 17 00:00:00 2001
-From: Quentin Armitage <quentin@armitage.org.uk>
-Date: Sat, 14 Oct 2023 15:37:19 +0100
-Subject: [PATCH] vrrp: Set sysctl arp_ignore to 1 on IPv6 VMACs
-
-Setting arp_ignore to 1 ensures that the VMAC interface does not respond
-to ARP requests for IPv4 addresses not configured on the VMAC.
-
-Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
----
- keepalived/include/vrrp_if_config.h | 2 +-
- keepalived/vrrp/vrrp_if_config.c | 28 ++++++++++++++++++++--------
- keepalived/vrrp/vrrp_vmac.c | 5 ++---
- 3 files changed, 23 insertions(+), 12 deletions(-)
-
-diff --git a/keepalived/include/vrrp_if_config.h b/keepalived/include/vrrp_if_config.h
-index 35465cd..c35e56e 100644
---- a/keepalived/include/vrrp_if_config.h
-+++ b/keepalived/include/vrrp_if_config.h
-@@ -34,7 +34,7 @@ extern void set_promote_secondaries(interface_t*);
- extern void reset_promote_secondaries(interface_t*);
- #ifdef _HAVE_VRRP_VMAC_
- extern void restore_rp_filter(void);
--extern void set_interface_parameters(const interface_t*, interface_t*);
-+extern void set_interface_parameters(const interface_t*, interface_t*, sa_family_t);
- extern void reset_interface_parameters(interface_t*);
- extern void link_set_ipv6(const interface_t*, bool);
- #endif
-diff --git a/keepalived/vrrp/vrrp_if_config.c b/keepalived/vrrp/vrrp_if_config.c
-index cfce7e2..fbfd34c 100644
---- a/keepalived/vrrp/vrrp_if_config.c
-+++ b/keepalived/vrrp/vrrp_if_config.c
-@@ -81,6 +81,11 @@ static sysctl_opts_t vmac_sysctl[] = {
- { 0, 0}
- };
-
-+static sysctl_opts_t vmac_sysctl_6[] = {
-+ { IPV4_DEVCONF_ARP_IGNORE, 1 },
-+ { 0, 0}
-+};
-+
- #endif
- #endif
-
-@@ -216,11 +221,14 @@ netlink_set_interface_flags(unsigned ifindex, const sysctl_opts_t *sys_opts)
-
- #ifdef _HAVE_VRRP_VMAC_
- static inline int
--netlink_set_interface_parameters(const interface_t *ifp, interface_t *base_ifp)
-+netlink_set_interface_parameters(const interface_t *ifp, interface_t *base_ifp, sa_family_t family)
- {
-- if (netlink_set_interface_flags(ifp->ifindex, vmac_sysctl))
-+ if (netlink_set_interface_flags(ifp->ifindex, family == AF_INET6 ? vmac_sysctl_6 : vmac_sysctl))
- return -1;
-
-+ if (family == AF_INET6)
-+ return 0;
-+
- /* If the underlying interface is a MACVLAN that has been moved into
- * a separate network namespace from the parent, we can't access the
- * parent. */
-@@ -271,9 +279,9 @@ netlink_reset_interface_parameters(const interface_t* ifp)
- }
-
- static inline void
--set_interface_parameters_devconf(const interface_t *ifp, interface_t *base_ifp)
-+set_interface_parameters_devconf(const interface_t *ifp, interface_t *base_ifp, sa_family_t family)
- {
-- if (netlink_set_interface_parameters(ifp, base_ifp))
-+ if (netlink_set_interface_parameters(ifp, base_ifp, family))
- log_message(LOG_INFO, "Unable to set parameters for %s", ifp->ifname);
- }
-
-@@ -310,11 +318,15 @@ reset_promote_secondaries_devconf(interface_t *ifp)
-
- #ifdef _HAVE_VRRP_VMAC_
- static inline void
--set_interface_parameters_sysctl(const interface_t *ifp, interface_t *base_ifp)
-+set_interface_parameters_sysctl(const interface_t *ifp, interface_t *base_ifp, sa_family_t family)
- {
- unsigned val;
-
- set_sysctl("net/ipv4/conf", ifp->ifname, "arp_ignore", 1);
-+
-+ if (family == AF_INET6)
-+ return;
-+
- set_sysctl("net/ipv4/conf", ifp->ifname, "accept_local", 1);
- set_sysctl("net/ipv4/conf", ifp->ifname, "rp_filter", 0);
-
-@@ -524,15 +536,15 @@ restore_rp_filter(void)
- }
-
- void
--set_interface_parameters(const interface_t *ifp, interface_t *base_ifp)
-+set_interface_parameters(const interface_t *ifp, interface_t *base_ifp, sa_family_t family)
- {
- if (all_rp_filter == UINT_MAX)
- clear_rp_filter();
-
- #ifdef _HAVE_IPV4_DEVCONF_
-- set_interface_parameters_devconf(ifp, base_ifp);
-+ set_interface_parameters_devconf(ifp, base_ifp, family);
- #else
-- set_interface_parameters_sysctl(ifp, base_ifp);
-+ set_interface_parameters_sysctl(ifp, base_ifp, family);
- #endif
- }
-
-diff --git a/keepalived/vrrp/vrrp_vmac.c b/keepalived/vrrp/vrrp_vmac.c
-index e5ff0e9..021953a 100644
---- a/keepalived/vrrp/vrrp_vmac.c
-+++ b/keepalived/vrrp/vrrp_vmac.c
-@@ -407,10 +407,9 @@ netlink_link_add_vmac(vrrp_t *vrrp, const interface_t *old_interface)
- if (!ifp->ifindex)
- return false;
-
-- if (vrrp->family == AF_INET && create_interface) {
-+ if (create_interface) {
- /* Set the necessary kernel parameters to make macvlans work for us */
--// If this saves current base_ifp's settings, we need to be careful if multiple VMACs on same i/f
-- set_interface_parameters(ifp, ifp->base_ifp);
-+ set_interface_parameters(ifp, ifp->base_ifp, vrrp->family);
- }
-
- #ifdef _WITH_FIREWALL_
---
-2.34.1
-
diff --git a/scripts/package-build/libnss-mapuser/.gitignore b/scripts/package-build/libnss-mapuser/.gitignore
new file mode 100644
index 00000000..15657c19
--- /dev/null
+++ b/scripts/package-build/libnss-mapuser/.gitignore
@@ -0,0 +1 @@
+/libnss-mapuser/
diff --git a/scripts/package-build/libnss-mapuser/build.py b/scripts/package-build/libnss-mapuser/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/libnss-mapuser/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/libnss-mapuser/package.toml b/scripts/package-build/libnss-mapuser/package.toml
new file mode 100644
index 00000000..20ff65b4
--- /dev/null
+++ b/scripts/package-build/libnss-mapuser/package.toml
@@ -0,0 +1,9 @@
+[[packages]]
+name = "libnss-mapuser"
+commit_id = "current"
+scm_url = "https://github.com/vyos/libnss-mapuser.git"
+
+[dependencies]
+packages = [
+ "libaudit-dev"
+]
diff --git a/scripts/package-build/libpam-radius-auth/.gitignore b/scripts/package-build/libpam-radius-auth/.gitignore
new file mode 100644
index 00000000..b6ba8742
--- /dev/null
+++ b/scripts/package-build/libpam-radius-auth/.gitignore
@@ -0,0 +1 @@
+/libpam-radius-auth/
diff --git a/scripts/package-build/libpam-radius-auth/build.py b/scripts/package-build/libpam-radius-auth/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/libpam-radius-auth/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/libpam-radius-auth/package.toml b/scripts/package-build/libpam-radius-auth/package.toml
new file mode 100644
index 00000000..d2c760c8
--- /dev/null
+++ b/scripts/package-build/libpam-radius-auth/package.toml
@@ -0,0 +1,10 @@
+[[packages]]
+name = "libpam-radius-auth"
+commit_id = "current"
+scm_url = "https://github.com/vyos/libpam-radius-auth.git"
+
+[dependencies]
+packages = [
+ "libpam-dev",
+ "libaudit-dev"
+]
diff --git a/scripts/package-build/linux-kernel/.gitignore b/scripts/package-build/linux-kernel/.gitignore
index 0a18ea8c..f1fb5374 100644
--- a/scripts/package-build/linux-kernel/.gitignore
+++ b/scripts/package-build/linux-kernel/.gitignore
@@ -9,6 +9,7 @@
/ovpn-dco
/nat-rtsp*
/jool*
+/ipt-netflow*
/qat*
/QAT*
*.tar.gz
@@ -18,13 +19,12 @@
# Intel Driver source
i40e-*/
igb-*/
-ixgbe-*/
-ixgbevf-*/
+ethernet-linux-*/
vyos-intel-*/
vyos-linux-firmware*/
kernel-vars
r8152-*.tar.bz2
-
+ephemeral.*
*.buildinfo
*.build
*.changes
diff --git a/scripts/package-build/linux-kernel/README.md b/scripts/package-build/linux-kernel/README.md
index 56954e5a..927e880c 100644
--- a/scripts/package-build/linux-kernel/README.md
+++ b/scripts/package-build/linux-kernel/README.md
@@ -5,9 +5,9 @@
# About
-VyOS runs on a custom Linux Kernel (which is 4.19) at the time of this writing.
-This repository holds a Jenkins Pipeline which is used to build the Custom
-Kernel (x86_64/amd64 at the moment) and all required out-of tree modules.
+VyOS runs on a custom Linux Kernel (which is 6.6) at the time of this writing.
+This repository holds build scripts that are used to build the Custom Kernel
+(x86_64/amd64 at the moment) and all required out-of tree modules.
VyOS does not utilize the build in Intel Kernel drivers for its NICs as those
Kernels sometimes lack features e.g. configurable receive-side-scaling queues.
@@ -33,9 +33,3 @@ VyOS utilizes several Out-of-Tree modules (e.g. WireGuard, Accel-PPP and Intel
network interface card drivers). Module source code is retrieved from the
upstream repository and - when needed - patched so it can be build using this
pipeline.
-
-In the past VyOS maintainers had a fork of the Linux Kernel, WireGuard and
-Accel-PPP. This is fine but increases maintenance effort. By utilizing vanilla
-repositories upgrading to new versions is very easy - only the branch/commit/tag
-used when cloning the repository via [Jenkinsfile](Jenkinsfile) needs to be
-adjusted.
diff --git a/scripts/package-build/linux-kernel/arch b/scripts/package-build/linux-kernel/arch
deleted file mode 120000
index f5f81fdc..00000000
--- a/scripts/package-build/linux-kernel/arch
+++ /dev/null
@@ -1 +0,0 @@
-../../../packages/linux-kernel/arch \ No newline at end of file
diff --git a/scripts/package-build/linux-kernel/arch/arm64/configs/vyos_defconfig b/scripts/package-build/linux-kernel/arch/arm64/configs/vyos_defconfig
new file mode 100644
index 00000000..e6ea3893
--- /dev/null
+++ b/scripts/package-build/linux-kernel/arch/arm64/configs/vyos_defconfig
@@ -0,0 +1,7274 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm64 6.6.15 Kernel Configuration
+#
+CONFIG_CC_VERSION_TEXT="gcc (Debian 12.2.0-14) 12.2.0"
+CONFIG_CC_IS_GCC=y
+CONFIG_GCC_VERSION=120200
+CONFIG_CLANG_VERSION=0
+CONFIG_AS_IS_GNU=y
+CONFIG_AS_VERSION=24000
+CONFIG_LD_IS_BFD=y
+CONFIG_LD_VERSION=24000
+CONFIG_LLD_VERSION=0
+CONFIG_CC_CAN_LINK=y
+CONFIG_CC_CAN_LINK_STATIC=y
+CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
+CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
+CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
+CONFIG_PAHOLE_VERSION=0
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_TABLE_SORT=y
+CONFIG_THREAD_INFO_IN_TASK=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_WERROR is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_BUILD_SALT=""
+CONFIG_DEFAULT_INIT=""
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_WATCH_QUEUE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_USELIB=y
+CONFIG_AUDIT=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_AUDITSYSCALL=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_INJECTION=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y
+CONFIG_GENERIC_IRQ_IPI=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_IRQ_MSI_IOMMU=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_GENERIC_IRQ_DEBUGFS is not set
+# end of IRQ subsystem
+
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+# CONFIG_NO_HZ_FULL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+# end of Timers subsystem
+
+CONFIG_BPF=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
+
+#
+# BPF subsystem
+#
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_JIT=y
+# CONFIG_BPF_JIT_ALWAYS_ON is not set
+CONFIG_BPF_JIT_DEFAULT_ON=y
+# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
+# CONFIG_BPF_PRELOAD is not set
+# end of BPF subsystem
+
+CONFIG_PREEMPT_BUILD=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_COUNT=y
+CONFIG_PREEMPTION=y
+CONFIG_PREEMPT_DYNAMIC=y
+# CONFIG_SCHED_CORE is not set
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_PSI is not set
+# end of CPU/Task time and stats accounting
+
+CONFIG_CPU_ISOLATION=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_TREE_SRCU=y
+CONFIG_TASKS_RCU_GENERIC=y
+CONFIG_TASKS_RCU=y
+CONFIG_TASKS_TRACE_RCU=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_NEED_SEGCBLIST=y
+# end of RCU Subsystem
+
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_IKHEADERS is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_PRINTK_INDEX is not set
+CONFIG_GENERIC_SCHED_CLOCK=y
+
+#
+# Scheduler features
+#
+# CONFIG_UCLAMP_TASK is not set
+# end of Scheduler features
+
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+CONFIG_CC_HAS_INT128=y
+CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
+CONFIG_GCC11_NO_ARRAY_BOUNDS=y
+CONFIG_CC_NO_ARRAY_BOUNDS=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_NUMA_BALANCING=y
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_CGROUPS=y
+CONFIG_PAGE_COUNTER=y
+# CONFIG_CGROUP_FAVOR_DYNMODS is not set
+CONFIG_MEMCG=y
+CONFIG_MEMCG_KMEM=y
+# CONFIG_BLK_CGROUP is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_SCHED_MM_CID=y
+CONFIG_CGROUP_PIDS=y
+# CONFIG_CGROUP_RDMA is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_HUGETLB is not set
+CONFIG_CPUSETS=y
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_CGROUP_PERF is not set
+CONFIG_CGROUP_BPF=y
+# CONFIG_CGROUP_MISC is not set
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_SOCK_CGROUP_DATA=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_TIME_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_RD_ZSTD=y
+# CONFIG_BOOT_CONFIG is not set
+CONFIG_INITRAMFS_PRESERVE_MTIME=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_LD_ORPHAN_WARN=y
+CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
+CONFIG_SYSCTL=y
+CONFIG_HAVE_UID16=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+CONFIG_MULTIUSER=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_FHANDLE=y
+CONFIG_POSIX_TIMERS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_FUTEX_PI=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_IO_URING is not set
+CONFIG_ADVISE_SYSCALLS=y
+CONFIG_MEMBARRIER=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_SELFTEST is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_BASE_RELATIVE=y
+CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
+# CONFIG_KCMP is not set
+CONFIG_RSEQ=y
+CONFIG_CACHESTAT_SYSCALL=y
+# CONFIG_DEBUG_RSEQ is not set
+CONFIG_HAVE_PERF_EVENTS=y
+# CONFIG_PC104 is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# end of Kernel Performance Events And Counters
+
+CONFIG_SYSTEM_DATA_VERIFICATION=y
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+
+#
+# Kexec and crash features
+#
+CONFIG_CRASH_CORE=y
+CONFIG_KEXEC_CORE=y
+CONFIG_KEXEC=y
+# CONFIG_KEXEC_FILE is not set
+# CONFIG_CRASH_DUMP is not set
+# end of Kexec and crash features
+# end of General setup
+
+CONFIG_ARM64=y
+CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_ARM64_PAGE_SHIFT=12
+CONFIG_ARM64_CONT_PTE_SHIFT=4
+CONFIG_ARM64_CONT_PMD_SHIFT=4
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=33
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SMP=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y
+
+#
+# Platform selection
+#
+# CONFIG_ARCH_ACTIONS is not set
+CONFIG_ARCH_SUNXI=y
+# CONFIG_ARCH_ALPINE is not set
+# CONFIG_ARCH_APPLE is not set
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+# CONFIG_ARCH_BCM_IPROC is not set
+# CONFIG_ARCH_BCMBCA is not set
+# CONFIG_ARCH_BRCMSTB is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_BITMAIN is not set
+# CONFIG_ARCH_EXYNOS is not set
+# CONFIG_ARCH_SPARX5 is not set
+CONFIG_ARCH_K3=y
+# CONFIG_ARCH_LG1K is not set
+CONFIG_ARCH_HISI=y
+# CONFIG_ARCH_KEEMBAY is not set
+# CONFIG_ARCH_MEDIATEK is not set
+CONFIG_ARCH_MESON=y
+CONFIG_ARCH_MVEBU=y
+CONFIG_ARCH_NXP=y
+CONFIG_ARCH_LAYERSCAPE=y
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_S32 is not set
+# CONFIG_ARCH_MA35 is not set
+# CONFIG_ARCH_NPCM is not set
+CONFIG_ARCH_QCOM=y
+# CONFIG_ARCH_REALTEK is not set
+CONFIG_ARCH_RENESAS=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_SEATTLE=y
+# CONFIG_ARCH_INTEL_SOCFPGA is not set
+# CONFIG_ARCH_STM32 is not set
+CONFIG_ARCH_SYNQUACER=y
+CONFIG_ARCH_TEGRA=y
+# CONFIG_ARCH_SPRD is not set
+CONFIG_ARCH_THUNDER=y
+CONFIG_ARCH_THUNDER2=y
+# CONFIG_ARCH_UNIPHIER is not set
+CONFIG_ARCH_VEXPRESS=y
+# CONFIG_ARCH_VISCONTI is not set
+CONFIG_ARCH_XGENE=y
+# CONFIG_ARCH_ZYNQMP is not set
+# end of Platform selection
+
+#
+# Kernel Features
+#
+
+#
+# ARM errata workarounds via the alternatives framework
+#
+CONFIG_AMPERE_ERRATUM_AC03_CPU_38=y
+CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
+CONFIG_ARM64_ERRATUM_826319=y
+CONFIG_ARM64_ERRATUM_827319=y
+CONFIG_ARM64_ERRATUM_824069=y
+CONFIG_ARM64_ERRATUM_819472=y
+CONFIG_ARM64_ERRATUM_832075=y
+CONFIG_ARM64_ERRATUM_1742098=y
+CONFIG_ARM64_ERRATUM_845719=y
+CONFIG_ARM64_ERRATUM_843419=y
+CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y
+CONFIG_ARM64_ERRATUM_1024718=y
+CONFIG_ARM64_ERRATUM_1418040=y
+CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y
+CONFIG_ARM64_ERRATUM_1165522=y
+CONFIG_ARM64_ERRATUM_1319367=y
+CONFIG_ARM64_ERRATUM_1530923=y
+CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
+CONFIG_ARM64_ERRATUM_2441007=y
+CONFIG_ARM64_ERRATUM_1286807=y
+CONFIG_ARM64_ERRATUM_1463225=y
+CONFIG_ARM64_ERRATUM_1542419=y
+CONFIG_ARM64_ERRATUM_1508412=y
+CONFIG_ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE=y
+CONFIG_ARM64_ERRATUM_2051678=y
+CONFIG_ARM64_ERRATUM_2077057=y
+CONFIG_ARM64_ERRATUM_2658417=y
+CONFIG_ARM64_ERRATUM_2119858=y
+CONFIG_ARM64_ERRATUM_2139208=y
+CONFIG_ARM64_WORKAROUND_TSB_FLUSH_FAILURE=y
+CONFIG_ARM64_ERRATUM_2054223=y
+CONFIG_ARM64_ERRATUM_2067961=y
+CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE=y
+CONFIG_ARM64_ERRATUM_2253138=y
+CONFIG_ARM64_ERRATUM_2224489=y
+CONFIG_ARM64_ERRATUM_2441009=y
+CONFIG_ARM64_ERRATUM_2064142=y
+CONFIG_ARM64_ERRATUM_2038923=y
+CONFIG_ARM64_ERRATUM_1902691=y
+CONFIG_ARM64_ERRATUM_2457168=y
+CONFIG_ARM64_ERRATUM_2645198=y
+CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD=y
+CONFIG_ARM64_ERRATUM_2966298=y
+CONFIG_ARM64_ERRATUM_3117295=y
+CONFIG_CAVIUM_ERRATUM_22375=y
+CONFIG_CAVIUM_ERRATUM_23144=y
+CONFIG_CAVIUM_ERRATUM_23154=y
+CONFIG_CAVIUM_ERRATUM_27456=y
+CONFIG_CAVIUM_ERRATUM_30115=y
+CONFIG_CAVIUM_TX2_ERRATUM_219=y
+CONFIG_FUJITSU_ERRATUM_010001=y
+CONFIG_HISILICON_ERRATUM_161600802=y
+CONFIG_QCOM_FALKOR_ERRATUM_1003=y
+CONFIG_QCOM_FALKOR_ERRATUM_1009=y
+CONFIG_QCOM_QDF2400_ERRATUM_0065=y
+CONFIG_QCOM_FALKOR_ERRATUM_E1041=y
+CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=y
+CONFIG_ROCKCHIP_ERRATUM_3588001=y
+CONFIG_SOCIONEXT_SYNQUACER_PREITS=y
+# end of ARM errata workarounds via the alternatives framework
+
+CONFIG_ARM64_4K_PAGES=y
+# CONFIG_ARM64_16K_PAGES is not set
+# CONFIG_ARM64_64K_PAGES is not set
+# CONFIG_ARM64_VA_BITS_39 is not set
+CONFIG_ARM64_VA_BITS_48=y
+CONFIG_ARM64_VA_BITS=48
+CONFIG_ARM64_PA_BITS_48=y
+CONFIG_ARM64_PA_BITS=48
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SCHED_MC=y
+# CONFIG_SCHED_CLUSTER is not set
+CONFIG_SCHED_SMT=y
+CONFIG_NR_CPUS=256
+CONFIG_HOTPLUG_CPU=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=6
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_CC_HAVE_SHADOW_CALL_STACK=y
+CONFIG_PARAVIRT=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_ARCH_SUPPORTS_KEXEC=y
+CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y
+CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y
+CONFIG_ARCH_SUPPORTS_KEXEC_IMAGE_VERIFY_SIG=y
+CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y
+CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y
+CONFIG_TRANS_TABLE=y
+CONFIG_XEN_DOM0=y
+CONFIG_XEN=y
+CONFIG_ARCH_FORCE_MAX_ORDER=10
+CONFIG_UNMAP_KERNEL_AT_EL0=y
+CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y
+CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
+# CONFIG_ARM64_SW_TTBR0_PAN is not set
+CONFIG_ARM64_TAGGED_ADDR_ABI=y
+CONFIG_COMPAT=y
+CONFIG_KUSER_HELPERS=y
+CONFIG_COMPAT_ALIGNMENT_FIXUPS=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+
+#
+# ARMv8.1 architectural features
+#
+CONFIG_ARM64_HW_AFDBM=y
+CONFIG_ARM64_PAN=y
+CONFIG_AS_HAS_LSE_ATOMICS=y
+CONFIG_ARM64_LSE_ATOMICS=y
+CONFIG_ARM64_USE_LSE_ATOMICS=y
+# end of ARMv8.1 architectural features
+
+#
+# ARMv8.2 architectural features
+#
+CONFIG_AS_HAS_ARMV8_2=y
+CONFIG_AS_HAS_SHA3=y
+CONFIG_ARM64_PMEM=y
+CONFIG_ARM64_RAS_EXTN=y
+CONFIG_ARM64_CNP=y
+# end of ARMv8.2 architectural features
+
+#
+# ARMv8.3 architectural features
+#
+CONFIG_ARM64_PTR_AUTH=y
+CONFIG_ARM64_PTR_AUTH_KERNEL=y
+CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y
+CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
+CONFIG_AS_HAS_ARMV8_3=y
+CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y
+CONFIG_AS_HAS_LDAPR=y
+# end of ARMv8.3 architectural features
+
+#
+# ARMv8.4 architectural features
+#
+CONFIG_ARM64_AMU_EXTN=y
+CONFIG_AS_HAS_ARMV8_4=y
+CONFIG_ARM64_TLB_RANGE=y
+# end of ARMv8.4 architectural features
+
+#
+# ARMv8.5 architectural features
+#
+CONFIG_AS_HAS_ARMV8_5=y
+CONFIG_ARM64_BTI=y
+CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y
+CONFIG_ARM64_E0PD=y
+CONFIG_ARM64_AS_HAS_MTE=y
+CONFIG_ARM64_MTE=y
+# end of ARMv8.5 architectural features
+
+#
+# ARMv8.7 architectural features
+#
+CONFIG_ARM64_EPAN=y
+# end of ARMv8.7 architectural features
+
+CONFIG_ARM64_SVE=y
+CONFIG_ARM64_SME=y
+# CONFIG_ARM64_PSEUDO_NMI is not set
+CONFIG_RELOCATABLE=y
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
+CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
+CONFIG_STACKPROTECTOR_PER_TASK=y
+# end of Kernel Features
+
+#
+# Boot options
+#
+CONFIG_ARM64_ACPI_PARKING_PROTOCOL=y
+CONFIG_CMDLINE=""
+CONFIG_EFI_STUB=y
+CONFIG_EFI=y
+CONFIG_DMI=y
+# end of Boot options
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_CLK=y
+CONFIG_PM_GENERIC_DOMAINS=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_CPU_PM=y
+# CONFIG_ENERGY_MODEL is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# end of Power management options
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Idle
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_CPU_IDLE_GOV_TEO is not set
+CONFIG_DT_IDLE_STATES=y
+CONFIG_DT_IDLE_GENPD=y
+
+#
+# ARM CPU Idle Drivers
+#
+CONFIG_ARM_PSCI_CPUIDLE=y
+CONFIG_ARM_PSCI_CPUIDLE_DOMAIN=y
+# end of ARM CPU Idle Drivers
+# end of CPU Idle
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+
+#
+# CPU frequency scaling drivers
+#
+CONFIG_CPUFREQ_DT=m
+CONFIG_CPUFREQ_DT_PLATDEV=y
+CONFIG_ACPI_CPPC_CPUFREQ=m
+CONFIG_ACPI_CPPC_CPUFREQ_FIE=y
+CONFIG_ARM_ARMADA_37XX_CPUFREQ=m
+# CONFIG_ARM_ARMADA_8K_CPUFREQ is not set
+CONFIG_ARM_SCPI_CPUFREQ=m
+CONFIG_ARM_IMX_CPUFREQ_DT=m
+CONFIG_ARM_QCOM_CPUFREQ_HW=m
+CONFIG_ARM_RASPBERRYPI_CPUFREQ=m
+# CONFIG_ARM_SCMI_CPUFREQ is not set
+CONFIG_ARM_TEGRA20_CPUFREQ=m
+CONFIG_ARM_TEGRA124_CPUFREQ=y
+CONFIG_ARM_TI_CPUFREQ=y
+CONFIG_QORIQ_CPUFREQ=m
+# end of CPU Frequency scaling
+# end of CPU Power Management
+
+CONFIG_ARCH_SUPPORTS_ACPI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_GENERIC_GSI=y
+CONFIG_ACPI_CCA_REQUIRED=y
+# CONFIG_ACPI_DEBUGGER is not set
+CONFIG_ACPI_SPCR_TABLE=y
+# CONFIG_ACPI_FPDT is not set
+# CONFIG_ACPI_EC_DEBUGFS is not set
+# CONFIG_ACPI_AC is not set
+# CONFIG_ACPI_BATTERY is not set
+CONFIG_ACPI_BUTTON=m
+# CONFIG_ACPI_TINY_POWER_BUTTON is not set
+CONFIG_ACPI_FAN=m
+# CONFIG_ACPI_TAD is not set
+# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_PROCESSOR_IDLE=y
+CONFIG_ACPI_MCFG=y
+CONFIG_ACPI_CPPC_LIB=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_IPMI=m
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_ACPI_THERMAL=m
+CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
+CONFIG_ACPI_TABLE_UPGRADE=y
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_PCI_SLOT=y
+CONFIG_ACPI_CONTAINER=y
+CONFIG_ACPI_HOTPLUG_MEMORY=y
+CONFIG_ACPI_HED=y
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+CONFIG_ACPI_BGRT=y
+CONFIG_ACPI_REDUCED_HARDWARE_ONLY=y
+CONFIG_ACPI_NFIT=m
+# CONFIG_NFIT_SECURITY_DEBUG is not set
+CONFIG_ACPI_NUMA=y
+# CONFIG_ACPI_HMAT is not set
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_ACPI_APEI=y
+CONFIG_ACPI_APEI_GHES=y
+CONFIG_ACPI_APEI_PCIEAER=y
+CONFIG_ACPI_APEI_SEA=y
+CONFIG_ACPI_APEI_MEMORY_FAILURE=y
+# CONFIG_ACPI_APEI_EINJ is not set
+# CONFIG_ACPI_APEI_ERST_DEBUG is not set
+# CONFIG_ACPI_CONFIGFS is not set
+# CONFIG_ACPI_PFRUT is not set
+CONFIG_ACPI_IORT=y
+CONFIG_ACPI_GTDT=y
+CONFIG_ACPI_APMT=y
+CONFIG_ACPI_PPTT=y
+CONFIG_ACPI_PCC=y
+# CONFIG_ACPI_FFH is not set
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_ACPI_PRMT=y
+CONFIG_IRQ_BYPASS_MANAGER=m
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
+
+#
+# General architecture-dependent options
+#
+CONFIG_ARCH_HAS_SUBPAGE_FAULTS=y
+CONFIG_HOTPLUG_CORE_SYNC=y
+CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
+# CONFIG_KPROBES is not set
+CONFIG_JUMP_LABEL=y
+# CONFIG_STATIC_KEYS_SELFTEST is not set
+CONFIG_UPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
+CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
+CONFIG_HAVE_NMI=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
+CONFIG_ARCH_HAS_KEEPINITRD=y
+CONFIG_ARCH_HAS_SET_MEMORY=y
+CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
+CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
+CONFIG_ARCH_WANTS_NO_INSTR=y
+CONFIG_HAVE_ASM_MODVERSIONS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_RSEQ=y
+CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
+CONFIG_MMU_GATHER_TABLE_FREE=y
+CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
+CONFIG_MMU_LAZY_TLB_REFCOUNT=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP=y
+CONFIG_SECCOMP_FILTER=y
+# CONFIG_SECCOMP_CACHE_DEBUG is not set
+CONFIG_HAVE_ARCH_STACKLEAK=y
+CONFIG_HAVE_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_SUPPORTS_SHADOW_CALL_STACK=y
+# CONFIG_SHADOW_CALL_STACK is not set
+CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
+CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
+CONFIG_LTO_NONE=y
+CONFIG_ARCH_SUPPORTS_CFI_CLANG=y
+CONFIG_HAVE_CONTEXT_TRACKING_USER=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOVE_PUD=y
+CONFIG_HAVE_MOVE_PMD=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_WANT_PMD_MKWRITE=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_COMPAT_OLD_SIGACTION=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_HAVE_ARCH_VMAP_STACK=y
+CONFIG_VMAP_STACK=y
+CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
+CONFIG_RANDOMIZE_KSTACK_OFFSET=y
+# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
+CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
+CONFIG_STRICT_MODULE_RWX=y
+CONFIG_HAVE_ARCH_COMPILER_H=y
+CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
+CONFIG_ARCH_USE_MEMREMAP_PROT=y
+# CONFIG_LOCK_EVENT_COUNTS is not set
+CONFIG_ARCH_HAS_RELR=y
+CONFIG_HAVE_PREEMPT_DYNAMIC=y
+CONFIG_HAVE_PREEMPT_DYNAMIC_KEY=y
+CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
+CONFIG_ARCH_HAVE_TRACE_MMIO_ACCESS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# end of GCOV-based kernel profiling
+
+CONFIG_HAVE_GCC_PLUGINS=y
+CONFIG_FUNCTION_ALIGNMENT_4B=y
+CONFIG_FUNCTION_ALIGNMENT=4
+# end of General architecture-dependent options
+
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_DEBUG is not set
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
+CONFIG_MODVERSIONS=y
+CONFIG_ASM_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+CONFIG_MODULE_COMPRESS_NONE=y
+# CONFIG_MODULE_COMPRESS_GZIP is not set
+# CONFIG_MODULE_COMPRESS_XZ is not set
+# CONFIG_MODULE_COMPRESS_ZSTD is not set
+# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
+CONFIG_MODPROBE_PATH="/sbin/modprobe"
+# CONFIG_TRIM_UNUSED_KSYMS is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_BLOCK=y
+CONFIG_BLOCK_LEGACY_AUTOLOAD=y
+CONFIG_BLK_DEV_BSG_COMMON=y
+CONFIG_BLK_ICQ=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BLK_DEV_INTEGRITY_T10=y
+# CONFIG_BLK_DEV_ZONED is not set
+CONFIG_BLK_WBT=y
+CONFIG_BLK_WBT_MQ=y
+CONFIG_BLK_DEBUG_FS=y
+CONFIG_BLK_SED_OPAL=y
+# CONFIG_BLK_INLINE_ENCRYPTION is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# end of Partition Types
+
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_BLK_PM=y
+CONFIG_BLOCK_HOLDER_DEPRECATED=y
+CONFIG_BLK_MQ_STACKING=y
+
+#
+# IO Schedulers
+#
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_MQ_IOSCHED_KYBER=y
+CONFIG_IOSCHED_BFQ=y
+# end of IO Schedulers
+
+CONFIG_PADATA=y
+CONFIG_ASN1=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
+CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
+CONFIG_FREEZER=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
+CONFIG_ARCH_HAVE_ELF_PROT=y
+CONFIG_ARCH_USE_GNU_PROPERTY=y
+CONFIG_ELFCORE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BINFMT_MISC=m
+CONFIG_COREDUMP=y
+# end of Executable file formats
+
+#
+# Memory Management options
+#
+# CONFIG_SWAP is not set
+
+#
+# SLAB allocator options
+#
+# CONFIG_SLAB_DEPRECATED is not set
+CONFIG_SLUB=y
+# CONFIG_SLUB_TINY is not set
+CONFIG_SLAB_MERGE_DEFAULT=y
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+# CONFIG_SLUB_STATS is not set
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_RANDOM_KMALLOC_CACHES is not set
+# end of SLAB allocator options
+
+# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_HAVE_FAST_GUP=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_NUMA_KEEP_MEMINFO=y
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_MEMORY_HOTPLUG=y
+# CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE is not set
+CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_MHP_MEMMAP_ON_MEMORY=y
+CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_MEMORY_BALLOON=y
+CONFIG_BALLOON_COMPACTION=y
+CONFIG_COMPACTION=y
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+CONFIG_PAGE_REPORTING=y
+CONFIG_MIGRATION=y
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
+CONFIG_ARCH_ENABLE_THP_MIGRATION=y
+CONFIG_CONTIG_ALLOC=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU_NOTIFIER=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_MEMORY_FAILURE=y
+# CONFIG_HWPOISON_INJECT is not set
+CONFIG_ARCH_WANTS_THP_SWAP=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
+# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
+# CONFIG_READ_ONLY_THP_FOR_FS is not set
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_USE_PERCPU_NUMA_NODE_ID=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_CMA=y
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+# CONFIG_CMA_SYSFS is not set
+CONFIG_CMA_AREAS=19
+CONFIG_GENERIC_EARLY_IOREMAP=y
+# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
+# CONFIG_IDLE_PAGE_TRACKING is not set
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y
+CONFIG_ARCH_HAS_PTE_DEVMAP=y
+CONFIG_ARCH_HAS_ZONE_DMA_SET=y
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA32=y
+# CONFIG_ZONE_DEVICE is not set
+CONFIG_HMM_MIRROR=y
+CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
+CONFIG_ARCH_USES_PG_ARCH_X=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_PERCPU_STATS is not set
+# CONFIG_GUP_TEST is not set
+# CONFIG_DMAPOOL_TEST is not set
+CONFIG_ARCH_HAS_PTE_SPECIAL=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_SECRETMEM=y
+# CONFIG_ANON_VMA_NAME is not set
+CONFIG_USERFAULTFD=y
+CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
+# CONFIG_LRU_GEN is not set
+CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y
+CONFIG_PER_VMA_LOCK=y
+CONFIG_LOCK_MM_AND_FIND_VMA=y
+
+#
+# Data Access Monitoring
+#
+# CONFIG_DAMON is not set
+# end of Data Access Monitoring
+# end of Memory Management options
+
+CONFIG_NET=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_EGRESS=y
+CONFIG_NET_XGRESS=y
+CONFIG_NET_REDIRECT=y
+CONFIG_SKB_EXTENSIONS=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_DIAG=m
+CONFIG_UNIX=y
+CONFIG_UNIX_SCM=y
+CONFIG_AF_UNIX_OOB=y
+CONFIG_UNIX_DIAG=m
+CONFIG_TLS=y
+CONFIG_TLS_DEVICE=y
+# CONFIG_TLS_TOE is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_OFFLOAD=y
+CONFIG_XFRM_ALGO=m
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_INTERFACE=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_AH=m
+CONFIG_XFRM_ESP=m
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_XFRM_ESPINTCP=y
+# CONFIG_SMC is not set
+CONFIG_XDP_SOCKETS=y
+# CONFIG_XDP_SOCKETS_DIAG is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IP_TUNNEL=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE_COMMON=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_UDP_TUNNEL=m
+CONFIG_NET_FOU=m
+CONFIG_NET_FOU_IP_TUNNELS=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_ESP_OFFLOAD=m
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TABLE_PERTURB_ORDER=16
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_INET_UDP_DIAG=m
+# CONFIG_INET_RAW_DIAG is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_NV=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_BBR=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_ESPINTCP=y
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_ILA=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_FOU=m
+CONFIG_IPV6_FOU_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_IPV6_SEG6_LWTUNNEL=y
+CONFIG_IPV6_SEG6_HMAC=y
+CONFIG_IPV6_SEG6_BPF=y
+# CONFIG_IPV6_RPL_LWTUNNEL is not set
+# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
+CONFIG_MPTCP=y
+CONFIG_INET_MPTCP_DIAG=m
+CONFIG_MPTCP_IPV6=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PTP_CLASSIFY=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_EGRESS=y
+CONFIG_NETFILTER_SKIP_EGRESS=y
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_FAMILY_BRIDGE=y
+CONFIG_NETFILTER_FAMILY_ARP=y
+CONFIG_NETFILTER_BPF_LINK=y
+# CONFIG_NETFILTER_NETLINK_HOOK is not set
+CONFIG_NETFILTER_NETLINK_ACCT=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_NETLINK_OSF=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_SYSLOG=m
+CONFIG_NETFILTER_CONNCOUNT=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_LABELS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_GRE=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_CT_NETLINK_TIMEOUT=m
+CONFIG_NF_CT_NETLINK_HELPER=m
+CONFIG_NETFILTER_NETLINK_GLUE_CT=y
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_NAT_MASQUERADE=y
+CONFIG_NETFILTER_SYNPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_REJECT_INET=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_XFRM=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
+CONFIG_NF_DUP_NETDEV=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+# CONFIG_NFT_REJECT_NETDEV is not set
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+# CONFIG_NF_FLOW_TABLE_PROCFS is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XTABLES_COMPAT=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_SET=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_NAT=m
+CONFIG_NETFILTER_XT_TARGET_NETMAP=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
+CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ECN=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# end of Core Netfilter Configuration
+
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_IPMAC=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_FO=m
+CONFIG_IP_VS_OVF=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+# CONFIG_IP_VS_MH is not set
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+# CONFIG_IP_VS_TWOS is not set
+
+#
+# IPVS SH scheduler
+#
+CONFIG_IP_VS_SH_TAB_BITS=8
+
+#
+# IPVS MH scheduler
+#
+CONFIG_IP_VS_MH_TAB_INDEX=12
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PE_SIP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_SOCKET_IPV4=m
+CONFIG_NF_TPROXY_IPV4=m
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_DUP_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
+CONFIG_NF_REJECT_IPV4=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# end of IP: Netfilter Configuration
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_SOCKET_IPV6=m
+CONFIG_NF_TPROXY_IPV6=m
+CONFIG_NF_TABLES_IPV6=y
+CONFIG_NFT_REJECT_IPV6=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_DUP_IPV6=m
+CONFIG_NF_REJECT_IPV6=m
+CONFIG_NF_LOG_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+# end of IPv6: Netfilter Configuration
+
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_TABLES_BRIDGE=m
+# CONFIG_NFT_BRIDGE_META is not set
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+# CONFIG_BPFILTER is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+# end of DCCP CCIDs Configuration
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# end of DCCP Kernel Hacking
+
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_OBJCNT is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_INET_SCTP_DIAG=m
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_MRP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_BRIDGE_VLAN_FILTERING=y
+# CONFIG_BRIDGE_MRP is not set
+# CONFIG_BRIDGE_CFM is not set
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_CBS=m
+CONFIG_NET_SCH_ETF=m
+CONFIG_NET_SCH_MQPRIO_LIB=m
+# CONFIG_NET_SCH_TAPRIO is not set
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_SKBPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+# CONFIG_NET_SCH_FQ_PIE is not set
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+# CONFIG_NET_SCH_ETS is not set
+# CONFIG_NET_SCH_DEFAULT is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+# CONFIG_NET_EMATCH_IPT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+# CONFIG_NET_ACT_SAMPLE is not set
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_MPLS=m
+CONFIG_NET_ACT_VLAN=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+# CONFIG_NET_ACT_CTINFO is not set
+CONFIG_NET_ACT_SKBMOD=m
+# CONFIG_NET_ACT_IFE is not set
+CONFIG_NET_ACT_TUNNEL_KEY=m
+# CONFIG_NET_ACT_CT is not set
+# CONFIG_NET_ACT_GATE is not set
+# CONFIG_NET_TC_SKB_EXT is not set
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+CONFIG_VSOCKETS=m
+CONFIG_VSOCKETS_DIAG=m
+CONFIG_VSOCKETS_LOOPBACK=m
+CONFIG_VMWARE_VMCI_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS_COMMON=m
+CONFIG_HYPERV_VSOCKETS=m
+CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
+CONFIG_NET_MPLS_GSO=y
+CONFIG_MPLS_ROUTING=m
+CONFIG_MPLS_IPTUNNEL=m
+# CONFIG_NET_NSH is not set
+CONFIG_HSR=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NET_L3_MASTER_DEV=y
+# CONFIG_QRTR is not set
+# CONFIG_NET_NCSI is not set
+CONFIG_PCPU_DEV_REFCNT=y
+CONFIG_MAX_SKB_FRAGS=17
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+CONFIG_XPS=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_NET_CLASSID=y
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_STREAM_PARSER is not set
+CONFIG_NET_FLOW_LIMIT=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_DROP_MONITOR=y
+# end of Network testing
+# end of Networking options
+
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AF_KCM is not set
+CONFIG_STREAM_PARSER=y
+# CONFIG_MCTP is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+CONFIG_CFG80211_CERTIFICATION_ONUS=y
+CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
+CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
+CONFIG_CFG80211_EXTRA_REGDB_KEYDIR=""
+# CONFIG_CFG80211_REG_CELLULAR_HINTS is not set
+# CONFIG_CFG80211_REG_RELAX_NO_IR is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+CONFIG_CFG80211_CRDA_SUPPORT=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_CFG80211_WEXT_EXPORT=y
+CONFIG_LIB80211=m
+CONFIG_LIB80211_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_RFKILL_GPIO is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+CONFIG_PSAMPLE=y
+# CONFIG_NET_IFE is not set
+CONFIG_LWTUNNEL=y
+CONFIG_LWTUNNEL_BPF=y
+CONFIG_DST_CACHE=y
+CONFIG_GRO_CELLS=y
+CONFIG_SOCK_VALIDATE_XMIT=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SOCK_MSG=y
+CONFIG_NET_DEVLINK=y
+CONFIG_PAGE_POOL=y
+# CONFIG_PAGE_POOL_STATS is not set
+CONFIG_FAILOVER=m
+CONFIG_ETHTOOL_NETLINK=y
+
+#
+# Device Drivers
+#
+CONFIG_ARM_AMBA=y
+CONFIG_TEGRA_AHB=y
+CONFIG_HAVE_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEAER_INJECT=m
+# CONFIG_PCIE_ECRC is not set
+CONFIG_PCIEASPM=y
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_POWERSAVE is not set
+# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+CONFIG_PCIE_PME=y
+CONFIG_PCIE_DPC=y
+CONFIG_PCIE_PTM=y
+# CONFIG_PCIE_EDR is not set
+CONFIG_PCI_MSI=y
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCI_STUB=m
+# CONFIG_PCI_PF_STUB is not set
+CONFIG_PCI_ATS=y
+CONFIG_PCI_ECAM=y
+CONFIG_PCI_BRIDGE_EMUL=y
+CONFIG_PCI_IOV=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_PASID=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_HYPERV=m
+# CONFIG_PCI_DYNAMIC_OF_NODES is not set
+# CONFIG_PCIE_BUS_TUNE_OFF is not set
+CONFIG_PCIE_BUS_DEFAULT=y
+# CONFIG_PCIE_BUS_SAFE is not set
+# CONFIG_PCIE_BUS_PERFORMANCE is not set
+# CONFIG_PCIE_BUS_PEER2PEER is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_SHPC=y
+
+#
+# PCI controller drivers
+#
+CONFIG_PCI_AARDVARK=y
+# CONFIG_PCIE_ALTERA is not set
+CONFIG_PCIE_BRCMSTB=y
+CONFIG_PCI_HOST_THUNDER_PEM=y
+CONFIG_PCI_HOST_THUNDER_ECAM=y
+# CONFIG_PCI_FTPCI100 is not set
+CONFIG_PCI_HOST_COMMON=y
+CONFIG_PCI_HOST_GENERIC=y
+# CONFIG_PCIE_HISI_ERR is not set
+# CONFIG_PCIE_MICROCHIP_HOST is not set
+CONFIG_PCI_HYPERV_INTERFACE=m
+CONFIG_PCI_TEGRA=y
+# CONFIG_PCIE_RCAR_HOST is not set
+CONFIG_PCIE_ROCKCHIP=y
+CONFIG_PCIE_ROCKCHIP_HOST=y
+CONFIG_PCI_XGENE=y
+CONFIG_PCI_XGENE_MSI=y
+# CONFIG_PCIE_XILINX is not set
+
+#
+# Cadence-based PCIe controllers
+#
+# CONFIG_PCIE_CADENCE_PLAT_HOST is not set
+# CONFIG_PCI_J721E_HOST is not set
+# end of Cadence-based PCIe controllers
+
+#
+# DesignWare-based PCIe controllers
+#
+# CONFIG_PCIE_AL is not set
+# CONFIG_PCI_MESON is not set
+# CONFIG_PCI_IMX6_HOST is not set
+# CONFIG_PCI_LAYERSCAPE is not set
+# CONFIG_PCI_HISI is not set
+# CONFIG_PCIE_KIRIN is not set
+# CONFIG_PCIE_HISI_STB is not set
+# CONFIG_PCIE_ARMADA_8K is not set
+# CONFIG_PCIE_DW_PLAT_HOST is not set
+# CONFIG_PCIE_QCOM is not set
+# CONFIG_PCIE_ROCKCHIP_DW_HOST is not set
+# CONFIG_PCI_KEYSTONE_HOST is not set
+# end of DesignWare-based PCIe controllers
+
+#
+# Mobiveil-based PCIe controllers
+#
+# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set
+# end of Mobiveil-based PCIe controllers
+# end of PCI controller drivers
+
+#
+# PCI Endpoint
+#
+# CONFIG_PCI_ENDPOINT is not set
+# end of PCI Endpoint
+
+#
+# PCI switch controller drivers
+#
+# CONFIG_PCI_SW_SWITCHTEC is not set
+# end of PCI switch controller drivers
+
+# CONFIG_CXL_BUS is not set
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_AUXILIARY_BUS=y
+# CONFIG_UEVENT_HELPER is not set
+CONFIG_DEVTMPFS=y
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DEVTMPFS_SAFE is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Firmware loader
+#
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_DEBUG=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_FW_LOADER_USER_HELPER=y
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+# CONFIG_FW_LOADER_COMPRESS is not set
+CONFIG_FW_CACHE=y
+# CONFIG_FW_UPLOAD is not set
+# end of Firmware loader
+
+CONFIG_WANT_DEV_COREDUMP=y
+CONFIG_ALLOW_DEV_COREDUMP=y
+CONFIG_DEV_COREDUMP=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
+# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
+CONFIG_SYS_HYPERVISOR=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_SOC_BUS=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_DMA_SHARED_BUFFER=y
+# CONFIG_DMA_FENCE_TRACE is not set
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_ARCH_NUMA=y
+# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set
+# end of Generic Driver Options
+
+#
+# Bus devices
+#
+# CONFIG_BRCMSTB_GISB_ARB is not set
+# CONFIG_HISILICON_LPC is not set
+# CONFIG_IMX_WEIM is not set
+CONFIG_QCOM_EBI2=y
+# CONFIG_QCOM_SSC_BLOCK_BUS is not set
+CONFIG_SUN50I_DE2_BUS=y
+CONFIG_SUNXI_RSB=y
+# CONFIG_TEGRA_GMI is not set
+CONFIG_TI_SYSC=y
+CONFIG_VEXPRESS_CONFIG=y
+CONFIG_FSL_MC_BUS=y
+# CONFIG_FSL_MC_UAPI_SUPPORT is not set
+# CONFIG_MHI_BUS is not set
+# CONFIG_MHI_BUS_EP is not set
+# end of Bus devices
+
+#
+# Cache Drivers
+#
+# end of Cache Drivers
+
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+
+#
+# Firmware Drivers
+#
+
+#
+# ARM System Control and Management Interface Protocol
+#
+CONFIG_ARM_SCMI_PROTOCOL=y
+# CONFIG_ARM_SCMI_RAW_MODE_SUPPORT is not set
+CONFIG_ARM_SCMI_HAVE_TRANSPORT=y
+CONFIG_ARM_SCMI_HAVE_SHMEM=y
+CONFIG_ARM_SCMI_TRANSPORT_MAILBOX=y
+CONFIG_ARM_SCMI_TRANSPORT_SMC=y
+# CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE is not set
+CONFIG_ARM_SCMI_POWER_DOMAIN=y
+# CONFIG_ARM_SCMI_POWER_CONTROL is not set
+# end of ARM System Control and Management Interface Protocol
+
+CONFIG_ARM_SCPI_PROTOCOL=m
+CONFIG_ARM_SCPI_POWER_DOMAIN=m
+# CONFIG_ARM_SDE_INTERFACE is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_DMIID=y
+CONFIG_DMI_SYSFS=y
+# CONFIG_ISCSI_IBFT is not set
+CONFIG_RASPBERRYPI_FIRMWARE=y
+# CONFIG_FW_CFG_SYSFS is not set
+CONFIG_QCOM_SCM=y
+# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set
+CONFIG_SYSFB=y
+CONFIG_SYSFB_SIMPLEFB=y
+CONFIG_TI_SCI_PROTOCOL=y
+CONFIG_TURRIS_MOX_RWTM=m
+# CONFIG_ARM_FFA_TRANSPORT is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# EFI (Extensible Firmware Interface) Support
+#
+CONFIG_EFI_ESRT=y
+CONFIG_EFI_VARS_PSTORE=m
+# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set
+CONFIG_EFI_PARAMS_FROM_FDT=y
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+CONFIG_EFI_GENERIC_STUB=y
+# CONFIG_EFI_ZBOOT is not set
+CONFIG_EFI_ARMSTUB_DTB_LOADER=y
+# CONFIG_EFI_BOOTLOADER_CONTROL is not set
+# CONFIG_EFI_CAPSULE_LOADER is not set
+# CONFIG_EFI_TEST is not set
+# CONFIG_RESET_ATTACK_MITIGATION is not set
+# CONFIG_EFI_DISABLE_PCI_DMA is not set
+CONFIG_EFI_EARLYCON=y
+CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
+# CONFIG_EFI_DISABLE_RUNTIME is not set
+# CONFIG_EFI_COCO_SECRET is not set
+# end of EFI (Extensible Firmware Interface) Support
+
+CONFIG_UEFI_CPER=y
+CONFIG_UEFI_CPER_ARM=y
+# CONFIG_IMX_DSP is not set
+# CONFIG_IMX_SCU is not set
+CONFIG_MESON_SM=y
+CONFIG_ARM_PSCI_FW=y
+# CONFIG_ARM_PSCI_CHECKER is not set
+CONFIG_HAVE_ARM_SMCCC=y
+CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
+CONFIG_ARM_SMCCC_SOC_ID=y
+
+#
+# Tegra firmware driver
+#
+# CONFIG_TEGRA_IVC is not set
+# end of Tegra firmware driver
+# end of Firmware Drivers
+
+# CONFIG_GNSS is not set
+# CONFIG_MTD is not set
+CONFIG_DTC=y
+CONFIG_OF=y
+# CONFIG_OF_UNITTEST is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+# CONFIG_OF_OVERLAY is not set
+CONFIG_OF_NUMA=y
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_1284 is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+
+#
+# Protocols
+#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_NULL_BLK=m
+CONFIG_CDROM=m
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_ZRAM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_XEN_BLKDEV_FRONTEND=m
+CONFIG_XEN_BLKDEV_BACKEND=m
+CONFIG_VIRTIO_BLK=m
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_UBLK is not set
+
+#
+# NVME Support
+#
+CONFIG_NVME_CORE=y
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+# CONFIG_NVME_VERBOSE_ERRORS is not set
+CONFIG_NVME_HWMON=y
+# CONFIG_NVME_RDMA is not set
+# CONFIG_NVME_FC is not set
+# CONFIG_NVME_TCP is not set
+# CONFIG_NVME_AUTH is not set
+# CONFIG_NVME_TARGET is not set
+# end of NVME Support
+
+#
+# Misc devices
+#
+CONFIG_SENSORS_LIS3LV02D=m
+CONFIG_AD525X_DPOT=m
+CONFIG_AD525X_DPOT_I2C=m
+# CONFIG_DUMMY_IRQ is not set
+CONFIG_PHANTOM=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIFM_7XX1=m
+CONFIG_ICS932S401=m
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_HP_ILO=m
+# CONFIG_QCOM_FASTRPC is not set
+CONFIG_APDS9802ALS=m
+CONFIG_ISL29003=m
+CONFIG_ISL29020=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_HMC6352=m
+CONFIG_DS1682=m
+CONFIG_SRAM=y
+# CONFIG_DW_XDATA_PCIE is not set
+# CONFIG_PCI_ENDPOINT_TEST is not set
+# CONFIG_XILINX_SDFEC is not set
+CONFIG_MISC_RTSX=m
+# CONFIG_OPEN_DICE is not set
+# CONFIG_VCPU_STALL_DETECTOR is not set
+CONFIG_C2PORT=m
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_EEPROM_MAX6875=m
+CONFIG_EEPROM_93CX6=m
+# CONFIG_EEPROM_IDT_89HPESX is not set
+# CONFIG_EEPROM_EE1004 is not set
+# end of EEPROM support
+
+CONFIG_CB710_CORE=m
+# CONFIG_CB710_DEBUG is not set
+CONFIG_CB710_DEBUG_ASSUMPTIONS=y
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# end of Texas Instruments shared transport line discipline
+
+CONFIG_SENSORS_LIS3_I2C=m
+CONFIG_ALTERA_STAPL=m
+CONFIG_VMWARE_VMCI=m
+# CONFIG_GENWQE is not set
+# CONFIG_ECHO is not set
+# CONFIG_BCM_VK is not set
+# CONFIG_MISC_ALCOR_PCI is not set
+CONFIG_MISC_RTSX_PCI=m
+CONFIG_MISC_RTSX_USB=m
+# CONFIG_UACCE is not set
+# CONFIG_PVPANIC is not set
+# CONFIG_GP_PCI1XXXX is not set
+# end of Misc devices
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_COMMON=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_NETLINK=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_ENCLOSURE is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SAS_HOST_SMP=y
+CONFIG_SCSI_SRP_ATTRS=m
+# end of SCSI Transports
+
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+# CONFIG_SCSI_HISI_SAS is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVSAS_TASKLET is not set
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT3SAS=m
+CONFIG_SCSI_MPT2SAS_MAX_SGE=128
+CONFIG_SCSI_MPT3SAS_MAX_SGE=128
+CONFIG_SCSI_MPT2SAS=m
+# CONFIG_SCSI_MPI3MR is not set
+CONFIG_SCSI_SMARTPQI=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_FLASHPOINT is not set
+# CONFIG_SCSI_MYRB is not set
+# CONFIG_SCSI_MYRS is not set
+CONFIG_XEN_SCSI_FRONTEND=m
+CONFIG_HYPERV_STORAGE=m
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_FCOE=m
+CONFIG_SCSI_SNIC=m
+# CONFIG_SCSI_SNIC_DEBUG_FS is not set
+CONFIG_SCSI_DMX3191D=m
+# CONFIG_SCSI_FDOMAIN_PCI is not set
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+# CONFIG_QEDI is not set
+# CONFIG_QEDF is not set
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_LPFC_DEBUG_FS is not set
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_VIRTIO=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+# end of SCSI device support
+
+CONFIG_ATA=m
+CONFIG_SATA_HOST=y
+CONFIG_PATA_TIMINGS=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATA_FORCE=y
+CONFIG_ATA_ACPI=y
+CONFIG_SATA_ZPODD=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_MOBILE_LPM_POLICY=3
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_AHCI_DWC is not set
+# CONFIG_AHCI_IMX is not set
+# CONFIG_AHCI_CEVA is not set
+# CONFIG_AHCI_MVEBU is not set
+# CONFIG_AHCI_SUNXI is not set
+# CONFIG_AHCI_TEGRA is not set
+# CONFIG_AHCI_QORIQ is not set
+# CONFIG_SATA_AHCI_SEATTLE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+CONFIG_ATA_PIIX=m
+# CONFIG_SATA_DWC is not set
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+# CONFIG_SATA_RCAR is not set
+CONFIG_SATA_SIL=m
+CONFIG_SATA_SIS=m
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+CONFIG_SATA_VIA=m
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IMX is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+CONFIG_PATA_OLDPIIX=m
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+CONFIG_PATA_SCH=m
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_SIL680=m
+CONFIG_PATA_SIS=m
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+CONFIG_PATA_VIA=m
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+CONFIG_PATA_MPIIX=m
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OF_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_PATA_ACPI is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_BITMAP_FILE=y
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID10=y
+CONFIG_MD_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_BCACHE is not set
+CONFIG_BLK_DEV_DM_BUILTIN=y
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_BUFIO=y
+# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
+# CONFIG_DM_UNSTRIPED is not set
+CONFIG_DM_CRYPT=y
+CONFIG_DM_SNAPSHOT=y
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_WRITECACHE is not set
+# CONFIG_DM_EBS is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_CLONE is not set
+# CONFIG_DM_MIRROR is not set
+CONFIG_DM_RAID=y
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_DUST is not set
+CONFIG_DM_INIT=y
+CONFIG_DM_UEVENT=y
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_LOG_WRITES is not set
+# CONFIG_DM_INTEGRITY is not set
+# CONFIG_DM_AUDIT is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_CTL=m
+# CONFIG_FUSION_LOGGING is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# end of IEEE 1394 (FireWire) support
+
+CONFIG_NETDEVICES=y
+CONFIG_MII=m
+CONFIG_NET_CORE=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+# CONFIG_WIREGUARD_DEBUG is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_FC is not set
+CONFIG_IFB=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN_L3S=y
+CONFIG_IPVLAN=m
+CONFIG_IPVTAP=m
+CONFIG_VXLAN=m
+CONFIG_GENEVE=m
+# CONFIG_BAREUDP is not set
+CONFIG_GTP=m
+# CONFIG_AMT is not set
+CONFIG_MACSEC=m
+# CONFIG_NETCONSOLE is not set
+CONFIG_TUN=m
+CONFIG_TAP=m
+# CONFIG_TUN_VNET_CROSS_LE is not set
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+CONFIG_NLMON=m
+CONFIG_NET_VRF=m
+# CONFIG_VSOCKMON is not set
+# CONFIG_ARCNET is not set
+CONFIG_ETHERNET=y
+CONFIG_MDIO=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_ET131X=m
+CONFIG_NET_VENDOR_ALACRITECH=y
+# CONFIG_SLICOSS is not set
+CONFIG_NET_VENDOR_ALLWINNER=y
+# CONFIG_SUN4I_EMAC is not set
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_ALTERA_TSE is not set
+CONFIG_NET_VENDOR_AMAZON=y
+CONFIG_ENA_ETHERNET=m
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_AMD8111_ETH=m
+CONFIG_PCNET32=m
+CONFIG_AMD_XGBE=m
+# CONFIG_AMD_XGBE_DCB is not set
+# CONFIG_PDS_CORE is not set
+# CONFIG_NET_XGENE is not set
+# CONFIG_NET_XGENE_V2 is not set
+CONFIG_NET_VENDOR_AQUANTIA=y
+CONFIG_AQTION=m
+# CONFIG_NET_VENDOR_ARC is not set
+CONFIG_NET_VENDOR_ASIX=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_ATL2=m
+CONFIG_ATL1=m
+CONFIG_ATL1E=m
+CONFIG_ATL1C=m
+CONFIG_ALX=m
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_B44=m
+CONFIG_B44_PCI_AUTOSELECT=y
+CONFIG_B44_PCICORE_AUTOSELECT=y
+CONFIG_B44_PCI=y
+# CONFIG_BCMGENET is not set
+CONFIG_BNX2=m
+CONFIG_CNIC=m
+CONFIG_TIGON3=m
+CONFIG_TIGON3_HWMON=y
+CONFIG_BNX2X=m
+CONFIG_BNX2X_SRIOV=y
+# CONFIG_SYSTEMPORT is not set
+CONFIG_BNXT=m
+CONFIG_BNXT_SRIOV=y
+CONFIG_BNXT_FLOWER_OFFLOAD=y
+# CONFIG_BNXT_DCB is not set
+CONFIG_BNXT_HWMON=y
+CONFIG_NET_VENDOR_CADENCE=y
+# CONFIG_MACB is not set
+CONFIG_NET_VENDOR_CAVIUM=y
+# CONFIG_THUNDER_NIC_PF is not set
+# CONFIG_THUNDER_NIC_VF is not set
+# CONFIG_THUNDER_NIC_BGX is not set
+# CONFIG_THUNDER_NIC_RGX is not set
+CONFIG_CAVIUM_PTP=y
+CONFIG_LIQUIDIO_CORE=m
+CONFIG_LIQUIDIO=m
+# CONFIG_LIQUIDIO_VF is not set
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T3=m
+CONFIG_CHELSIO_T4=m
+# CONFIG_CHELSIO_T4_DCB is not set
+CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_LIB=m
+CONFIG_CHELSIO_INLINE_CRYPTO=y
+# CONFIG_CHELSIO_IPSEC_INLINE is not set
+# CONFIG_CHELSIO_TLS_DEVICE is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_CORTINA is not set
+CONFIG_NET_VENDOR_DAVICOM=y
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_DEC is not set
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_DL2K=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_BE2NET=m
+CONFIG_BE2NET_HWMON=y
+CONFIG_BE2NET_BE2=y
+CONFIG_BE2NET_BE3=y
+CONFIG_BE2NET_LANCER=y
+CONFIG_BE2NET_SKYHAWK=y
+CONFIG_NET_VENDOR_ENGLEDER=y
+# CONFIG_TSNEP is not set
+CONFIG_NET_VENDOR_EZCHIP=y
+# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set
+CONFIG_NET_VENDOR_FREESCALE=y
+# CONFIG_FEC is not set
+# CONFIG_FSL_FMAN is not set
+# CONFIG_FSL_PQ_MDIO is not set
+# CONFIG_FSL_XGMAC_MDIO is not set
+# CONFIG_GIANFAR is not set
+# CONFIG_FSL_DPAA2_SWITCH is not set
+# CONFIG_FSL_ENETC is not set
+# CONFIG_FSL_ENETC_VF is not set
+# CONFIG_FSL_ENETC_IERB is not set
+# CONFIG_FSL_ENETC_MDIO is not set
+CONFIG_NET_VENDOR_FUNGIBLE=y
+# CONFIG_FUN_ETH is not set
+CONFIG_NET_VENDOR_GOOGLE=y
+CONFIG_GVE=m
+CONFIG_NET_VENDOR_HISILICON=y
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HISI_FEMAC is not set
+# CONFIG_HIP04_ETH is not set
+# CONFIG_HNS_DSAF is not set
+# CONFIG_HNS_ENET is not set
+# CONFIG_HNS3 is not set
+CONFIG_NET_VENDOR_HUAWEI=y
+CONFIG_HINIC=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_IGB=m
+CONFIG_IGB_HWMON=y
+CONFIG_IGBVF=m
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+CONFIG_I40E=m
+# CONFIG_I40E_DCB is not set
+CONFIG_IAVF=m
+CONFIG_I40EVF=m
+CONFIG_ICE=m
+CONFIG_ICE_SWITCHDEV=y
+# CONFIG_FM10K is not set
+CONFIG_IGC=m
+CONFIG_JME=m
+CONFIG_NET_VENDOR_LITEX=y
+# CONFIG_LITEX_LITEETH is not set
+CONFIG_NET_VENDOR_MARVELL=y
+# CONFIG_MVMDIO is not set
+# CONFIG_MVNETA is not set
+# CONFIG_MVPP2 is not set
+CONFIG_SKGE=m
+# CONFIG_SKGE_DEBUG is not set
+CONFIG_SKGE_GENESIS=y
+CONFIG_SKY2=m
+# CONFIG_SKY2_DEBUG is not set
+# CONFIG_OCTEONTX2_AF is not set
+# CONFIG_OCTEONTX2_PF is not set
+# CONFIG_OCTEON_EP is not set
+# CONFIG_PRESTERA is not set
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_MLX4_EN=m
+CONFIG_MLX4_EN_DCB=y
+CONFIG_MLX4_CORE=m
+CONFIG_MLX4_DEBUG=y
+CONFIG_MLX4_CORE_GEN2=y
+CONFIG_MLX5_CORE=m
+# CONFIG_MLX5_FPGA is not set
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_EN_ARFS=y
+CONFIG_MLX5_EN_RXNFC=y
+CONFIG_MLX5_MPFS=y
+CONFIG_MLX5_ESWITCH=y
+CONFIG_MLX5_BRIDGE=y
+CONFIG_MLX5_CORE_EN_DCB=y
+# CONFIG_MLX5_CORE_IPOIB is not set
+# CONFIG_MLX5_MACSEC is not set
+CONFIG_MLX5_EN_IPSEC=y
+CONFIG_MLX5_EN_TLS=y
+CONFIG_MLX5_SW_STEERING=y
+# CONFIG_MLX5_SF is not set
+CONFIG_MLXSW_CORE=m
+CONFIG_MLXSW_CORE_HWMON=y
+CONFIG_MLXSW_CORE_THERMAL=y
+CONFIG_MLXSW_PCI=m
+CONFIG_MLXSW_I2C=m
+CONFIG_MLXSW_SPECTRUM=m
+CONFIG_MLXSW_SPECTRUM_DCB=y
+CONFIG_MLXSW_MINIMAL=m
+CONFIG_MLXFW=m
+# CONFIG_MLXBF_GIGE is not set
+CONFIG_NET_VENDOR_MICREL=y
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_KSZ884X_PCI=m
+CONFIG_NET_VENDOR_MICROCHIP=y
+# CONFIG_LAN743X is not set
+# CONFIG_LAN966X_SWITCH is not set
+# CONFIG_VCAP is not set
+CONFIG_NET_VENDOR_MICROSEMI=y
+# CONFIG_MSCC_OCELOT_SWITCH is not set
+CONFIG_NET_VENDOR_MICROSOFT=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_MYRI10GE=m
+CONFIG_FEALNX=m
+# CONFIG_NET_VENDOR_NI is not set
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NATSEMI=m
+CONFIG_NS83820=m
+CONFIG_NET_VENDOR_NETERION=y
+CONFIG_S2IO=m
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_8390 is not set
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_FORCEDETH=m
+CONFIG_NET_VENDOR_OKI=y
+# CONFIG_ETHOC is not set
+CONFIG_NET_VENDOR_PACKET_ENGINES=y
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+# CONFIG_NET_VENDOR_PENSANDO is not set
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_QLCNIC_SRIOV=y
+CONFIG_QLCNIC_DCB=y
+CONFIG_QLCNIC_HWMON=y
+CONFIG_NETXEN_NIC=m
+CONFIG_QED=m
+CONFIG_QED_SRIOV=y
+CONFIG_QEDE=m
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_BNA=m
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RDC is not set
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_R8169=m
+CONFIG_NET_VENDOR_RENESAS=y
+# CONFIG_SH_ETH is not set
+# CONFIG_RAVB is not set
+# CONFIG_RENESAS_ETHER_SWITCH is not set
+CONFIG_NET_VENDOR_ROCKER=y
+# CONFIG_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_SC92031=m
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_SIS900=m
+CONFIG_SIS190=m
+CONFIG_NET_VENDOR_SOLARFLARE=y
+CONFIG_SFC=m
+CONFIG_SFC_MCDI_MON=y
+CONFIG_SFC_SRIOV=y
+CONFIG_SFC_MCDI_LOGGING=y
+CONFIG_SFC_FALCON=m
+# CONFIG_SFC_SIENA is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_STMMAC_ETH=m
+# CONFIG_STMMAC_SELFTESTS is not set
+CONFIG_STMMAC_PLATFORM=m
+# CONFIG_DWMAC_DWC_QOS_ETH is not set
+CONFIG_DWMAC_GENERIC=m
+CONFIG_DWMAC_IPQ806X=m
+CONFIG_DWMAC_MESON=m
+CONFIG_DWMAC_QCOM_ETHQOS=m
+CONFIG_DWMAC_ROCKCHIP=m
+CONFIG_DWMAC_SUNXI=m
+CONFIG_DWMAC_SUN8I=m
+CONFIG_DWMAC_IMX8=m
+# CONFIG_DWMAC_INTEL_PLAT is not set
+# CONFIG_DWMAC_TEGRA is not set
+# CONFIG_STMMAC_PCI is not set
+# CONFIG_NET_VENDOR_SUN is not set
+CONFIG_NET_VENDOR_SYNOPSYS=y
+# CONFIG_DWC_XLGMAC is not set
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_TEHUTI=m
+CONFIG_NET_VENDOR_TI=y
+# CONFIG_TI_DAVINCI_MDIO is not set
+# CONFIG_TI_CPSW_PHY_SEL is not set
+# CONFIG_TI_K3_AM65_CPSW_NUSS is not set
+# CONFIG_TI_K3_AM65_CPTS is not set
+CONFIG_TLAN=m
+CONFIG_NET_VENDOR_VERTEXCOM=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_VENDOR_WANGXUN=y
+# CONFIG_NGBE is not set
+# CONFIG_TXGBE is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_NET_SB1000 is not set
+CONFIG_PHYLINK=m
+CONFIG_PHYLIB=y
+CONFIG_SWPHY=y
+# CONFIG_LED_TRIGGER_PHY is not set
+CONFIG_PHYLIB_LEDS=y
+CONFIG_FIXED_PHY=y
+# CONFIG_SFP is not set
+
+#
+# MII PHY device drivers
+#
+CONFIG_AMD_PHY=m
+# CONFIG_MESON_GXL_PHY is not set
+# CONFIG_ADIN_PHY is not set
+# CONFIG_ADIN1100_PHY is not set
+CONFIG_AQUANTIA_PHY=m
+CONFIG_AX88796B_PHY=m
+CONFIG_BROADCOM_PHY=m
+# CONFIG_BCM54140_PHY is not set
+CONFIG_BCM7XXX_PHY=m
+# CONFIG_BCM84881_PHY is not set
+CONFIG_BCM87XX_PHY=m
+CONFIG_BCM_NET_PHYLIB=m
+CONFIG_CICADA_PHY=m
+CONFIG_CORTINA_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_INTEL_XWAY_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_MARVELL_10G_PHY=m
+# CONFIG_MARVELL_88Q2XXX_PHY is not set
+# CONFIG_MARVELL_88X2222_PHY is not set
+# CONFIG_MAXLINEAR_GPHY is not set
+# CONFIG_MEDIATEK_GE_PHY is not set
+CONFIG_MICREL_PHY=m
+# CONFIG_MICROCHIP_T1S_PHY is not set
+CONFIG_MICROCHIP_PHY=m
+CONFIG_MICROCHIP_T1_PHY=m
+CONFIG_MICROSEMI_PHY=m
+# CONFIG_MOTORCOMM_PHY is not set
+CONFIG_NATIONAL_PHY=m
+# CONFIG_NXP_CBTX_PHY is not set
+# CONFIG_NXP_C45_TJA11XX_PHY is not set
+# CONFIG_NXP_TJA11XX_PHY is not set
+# CONFIG_NCN26000_PHY is not set
+CONFIG_AT803X_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_RENESAS_PHY=m
+CONFIG_ROCKCHIP_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_STE10XP=m
+CONFIG_TERANETICS_PHY=m
+CONFIG_DP83822_PHY=m
+CONFIG_DP83TC811_PHY=m
+CONFIG_DP83848_PHY=m
+CONFIG_DP83867_PHY=m
+# CONFIG_DP83869_PHY is not set
+# CONFIG_DP83TD510_PHY is not set
+CONFIG_VITESSE_PHY=m
+# CONFIG_XILINX_GMII2RGMII is not set
+# CONFIG_PSE_CONTROLLER is not set
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_BUS=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_OF_MDIO=y
+CONFIG_ACPI_MDIO=y
+CONFIG_MDIO_DEVRES=y
+# CONFIG_MDIO_SUN4I is not set
+# CONFIG_MDIO_XGENE is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_HISI_FEMAC is not set
+# CONFIG_MDIO_MVUSB is not set
+# CONFIG_MDIO_MSCC_MIIM is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MDIO_IPQ4019 is not set
+# CONFIG_MDIO_IPQ8064 is not set
+# CONFIG_MDIO_THUNDER is not set
+
+#
+# MDIO Multiplexers
+#
+CONFIG_MDIO_BUS_MUX=m
+CONFIG_MDIO_BUS_MUX_MESON_G12A=m
+CONFIG_MDIO_BUS_MUX_MESON_GXL=m
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+
+#
+# PCS device drivers
+#
+CONFIG_PCS_XPCS=m
+# end of PCS device drivers
+
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+# CONFIG_PPPOE_HASH_BITS_1 is not set
+# CONFIG_PPPOE_HASH_BITS_2 is not set
+CONFIG_PPPOE_HASH_BITS_4=y
+# CONFIG_PPPOE_HASH_BITS_8 is not set
+CONFIG_PPPOE_HASH_BITS=4
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_USB_NET_DRIVERS=m
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_KALMIA is not set
+CONFIG_USB_NET_QMI_WWAN=m
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_USB_SIERRA_NET=m
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_NET_CH9200 is not set
+# CONFIG_USB_NET_AQC111 is not set
+CONFIG_USB_RTL8153_ECM=m
+CONFIG_WLAN=y
+CONFIG_WLAN_VENDOR_ADMTEK=y
+CONFIG_ADM8211=m
+CONFIG_ATH_COMMON=m
+CONFIG_WLAN_VENDOR_ATH=y
+# CONFIG_ATH_DEBUG is not set
+CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS=y
+CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING=y
+CONFIG_ATH5K=m
+# CONFIG_ATH5K_DEBUG is not set
+# CONFIG_ATH5K_TRACER is not set
+CONFIG_ATH5K_PCI=y
+# CONFIG_ATH5K_TEST_CHANNELS is not set
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_COMMON=m
+# CONFIG_ATH9K_BTCOEX_SUPPORT is not set
+CONFIG_ATH9K=m
+CONFIG_ATH9K_PCI=y
+# CONFIG_ATH9K_AHB is not set
+# CONFIG_ATH9K_DEBUGFS is not set
+# CONFIG_ATH9K_DFS_CERTIFIED is not set
+# CONFIG_ATH9K_DYNACK is not set
+# CONFIG_ATH9K_WOW is not set
+CONFIG_ATH9K_RFKILL=y
+CONFIG_ATH9K_CHANNEL_CONTEXT=y
+CONFIG_ATH9K_PCOEM=y
+# CONFIG_ATH9K_PCI_NO_EEPROM is not set
+CONFIG_ATH9K_HTC=m
+# CONFIG_ATH9K_HTC_DEBUGFS is not set
+# CONFIG_ATH9K_HWRNG is not set
+CONFIG_CARL9170=m
+CONFIG_CARL9170_LEDS=y
+CONFIG_CARL9170_WPC=y
+# CONFIG_CARL9170_HWRNG is not set
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_USB=m
+# CONFIG_ATH6KL_DEBUG is not set
+# CONFIG_ATH6KL_TRACING is not set
+# CONFIG_ATH6KL_REGDOMAIN is not set
+CONFIG_AR5523=m
+CONFIG_WIL6210=m
+CONFIG_WIL6210_ISR_COR=y
+# CONFIG_WIL6210_TRACING is not set
+CONFIG_WIL6210_DEBUGFS=y
+CONFIG_ATH10K=m
+CONFIG_ATH10K_CE=y
+CONFIG_ATH10K_PCI=m
+# CONFIG_ATH10K_AHB is not set
+CONFIG_ATH10K_SDIO=m
+CONFIG_ATH10K_USB=m
+# CONFIG_ATH10K_DEBUG is not set
+# CONFIG_ATH10K_DEBUGFS is not set
+# CONFIG_ATH10K_TRACING is not set
+CONFIG_ATH10K_DFS_CERTIFIED=y
+# CONFIG_WCN36XX is not set
+# CONFIG_ATH11K is not set
+# CONFIG_ATH12K is not set
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+CONFIG_WLAN_VENDOR_BROADCOM=y
+CONFIG_B43=m
+CONFIG_B43_BCMA=y
+CONFIG_B43_SSB=y
+CONFIG_B43_BUSES_BCMA_AND_SSB=y
+# CONFIG_B43_BUSES_BCMA is not set
+# CONFIG_B43_BUSES_SSB is not set
+CONFIG_B43_PCI_AUTOSELECT=y
+CONFIG_B43_PCICORE_AUTOSELECT=y
+CONFIG_B43_SDIO=y
+CONFIG_B43_BCMA_PIO=y
+CONFIG_B43_PIO=y
+CONFIG_B43_PHY_G=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_PHY_HT=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+# CONFIG_B43LEGACY is not set
+CONFIG_BRCMUTIL=m
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_PROTO_BCDC=y
+CONFIG_BRCMFMAC_PROTO_MSGBUF=y
+CONFIG_BRCMFMAC_SDIO=y
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMFMAC_PCIE=y
+# CONFIG_BRCM_TRACING is not set
+# CONFIG_BRCMDBG is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+CONFIG_WLAN_VENDOR_INTEL=y
+# CONFIG_IPW2100 is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW2200_RADIOTAP=y
+CONFIG_IPW2200_PROMISCUOUS=y
+CONFIG_IPW2200_QOS=y
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_LIBIPW=m
+# CONFIG_LIBIPW_DEBUG is not set
+CONFIG_IWLEGACY=m
+CONFIG_IWL4965=m
+CONFIG_IWL3945=m
+
+#
+# iwl3945 / iwl4965 Debugging Options
+#
+# CONFIG_IWLEGACY_DEBUG is not set
+# end of iwl3945 / iwl4965 Debugging Options
+
+CONFIG_IWLWIFI=m
+CONFIG_IWLWIFI_LEDS=y
+CONFIG_IWLDVM=m
+CONFIG_IWLMVM=m
+CONFIG_IWLWIFI_OPMODE_MODULAR=y
+
+#
+# Debugging Options
+#
+# CONFIG_IWLWIFI_DEBUG is not set
+CONFIG_IWLWIFI_DEVICE_TRACING=y
+# end of Debugging Options
+
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+CONFIG_WLAN_VENDOR_MARVELL=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+CONFIG_LIBERTAS_MESH=y
+CONFIG_LIBERTAS_THINFIRM=m
+# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MWIFIEX_PCIE=m
+CONFIG_MWIFIEX_USB=m
+CONFIG_MWL8K=m
+CONFIG_WLAN_VENDOR_MEDIATEK=y
+CONFIG_MT7601U=m
+CONFIG_MT76_CORE=m
+CONFIG_MT76_LEDS=y
+CONFIG_MT76_USB=m
+CONFIG_MT76_SDIO=m
+CONFIG_MT76x02_LIB=m
+CONFIG_MT76x02_USB=m
+CONFIG_MT76_CONNAC_LIB=m
+CONFIG_MT76x0_COMMON=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x0E=m
+CONFIG_MT76x2_COMMON=m
+CONFIG_MT76x2E=m
+CONFIG_MT76x2U=m
+CONFIG_MT7603E=m
+CONFIG_MT7615_COMMON=m
+CONFIG_MT7615E=m
+CONFIG_MT7663_USB_SDIO_COMMON=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+# CONFIG_MT7921E is not set
+# CONFIG_MT7921S is not set
+# CONFIG_MT7921U is not set
+# CONFIG_MT7996E is not set
+CONFIG_WLAN_VENDOR_MICROCHIP=y
+# CONFIG_WILC1000_SDIO is not set
+CONFIG_WLAN_VENDOR_PURELIFI=y
+# CONFIG_PLFXLC is not set
+CONFIG_WLAN_VENDOR_RALINK=y
+CONFIG_RT2X00=m
+CONFIG_RT2400PCI=m
+CONFIG_RT2500PCI=m
+CONFIG_RT61PCI=m
+CONFIG_RT2800PCI=m
+CONFIG_RT2800PCI_RT33XX=y
+CONFIG_RT2800PCI_RT35XX=y
+CONFIG_RT2800PCI_RT53XX=y
+CONFIG_RT2800PCI_RT3290=y
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+# CONFIG_RT2800USB_UNKNOWN is not set
+CONFIG_RT2800_LIB=m
+CONFIG_RT2800_LIB_MMIO=m
+CONFIG_RT2X00_LIB_MMIO=m
+CONFIG_RT2X00_LIB_PCI=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_WLAN_VENDOR_REALTEK=y
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+CONFIG_RTL_CARDS=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTLWIFI_PCI=m
+CONFIG_RTLWIFI_USB=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTL8723_COMMON=m
+CONFIG_RTLBTCOEXIST=m
+CONFIG_RTL8XXXU=m
+# CONFIG_RTL8XXXU_UNTESTED is not set
+# CONFIG_RTW88 is not set
+# CONFIG_RTW89 is not set
+CONFIG_WLAN_VENDOR_RSI=y
+CONFIG_RSI_91X=m
+CONFIG_RSI_DEBUGFS=y
+CONFIG_RSI_SDIO=m
+CONFIG_RSI_USB=m
+CONFIG_WLAN_VENDOR_SILABS=y
+# CONFIG_WFX is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+# CONFIG_WLAN_VENDOR_QUANTENNA is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+CONFIG_MAC80211_HWSIM=m
+# CONFIG_VIRT_WIFI is not set
+# CONFIG_WAN is not set
+
+#
+# Wireless WAN
+#
+# CONFIG_WWAN is not set
+# end of Wireless WAN
+
+CONFIG_XEN_NETDEV_FRONTEND=m
+CONFIG_XEN_NETDEV_BACKEND=m
+CONFIG_VMXNET3=m
+# CONFIG_FUJITSU_ES is not set
+CONFIG_HYPERV_NET=m
+# CONFIG_NETDEVSIM is not set
+CONFIG_NET_FAILOVER=m
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_SPARSEKMAP=m
+# CONFIG_INPUT_MATRIXKMAP is not set
+CONFIG_INPUT_VIVALDIFMAP=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1050 is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_DLINK_DIR685 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO_POLLED=m
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_SNVS_PWRKEY is not set
+# CONFIG_KEYBOARD_IMX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_TEGRA is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PINEPHONE is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_SUN4I_LRADC is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_CAP11XX is not set
+# CONFIG_KEYBOARD_BCM is not set
+# CONFIG_KEYBOARD_CYPRESS_SF is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
+# CONFIG_INPUT_BBNSM_PWRKEY is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_DECODER is not set
+# CONFIG_INPUT_GPIO_VIBRA is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+# CONFIG_INPUT_AXP20X_PEK is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_DA7280_HAPTICS is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_IBM_PANEL is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_IQS269A is not set
+# CONFIG_INPUT_IQS626A is not set
+# CONFIG_INPUT_IQS7222 is not set
+# CONFIG_INPUT_CMA3000 is not set
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2665_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_INPUT_HISI_POWERKEY is not set
+# CONFIG_RMI4_CORE is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_APBPS2 is not set
+CONFIG_HYPERV_KEYBOARD=m
+# CONFIG_SERIO_SUN4I_PS2 is not set
+# CONFIG_SERIO_GPIO_PS2 is not set
+# CONFIG_USERIO is not set
+# CONFIG_GAMEPORT is not set
+# end of Hardware I/O ports
+# end of Input device support
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_LEGACY_TIOCSTI=y
+CONFIG_LDISC_AUTOLOAD=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_EARLYCON=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_PNP=y
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
+CONFIG_SERIAL_8250_FINTEK=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DMA=y
+CONFIG_SERIAL_8250_PCILIB=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_EXAR=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+# CONFIG_SERIAL_8250_PCI1XXXX is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_DWLIB=y
+# CONFIG_SERIAL_8250_BCM2835AUX is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_DW=y
+# CONFIG_SERIAL_8250_EM is not set
+# CONFIG_SERIAL_8250_RT288X is not set
+# CONFIG_SERIAL_8250_OMAP is not set
+CONFIG_SERIAL_8250_PERICOM=y
+CONFIG_SERIAL_8250_TEGRA=y
+# CONFIG_SERIAL_OF_PLATFORM is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_SERIAL_EARLYCON_SEMIHOST is not set
+# CONFIG_SERIAL_MESON is not set
+# CONFIG_SERIAL_TEGRA is not set
+# CONFIG_SERIAL_IMX is not set
+# CONFIG_SERIAL_IMX_EARLYCON is not set
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_SH_SCI is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+# CONFIG_SERIAL_MSM is not set
+# CONFIG_SERIAL_SIFIVE is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_ARC is not set
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_RP2_NR_UARTS=32
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_FSL_LINFLEXUART is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+# CONFIG_SERIAL_SPRD is not set
+# CONFIG_SERIAL_MVEBU_UART is not set
+# end of Serial drivers
+
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_MOXA_INTELLIO=m
+CONFIG_MOXA_SMARTIO=m
+CONFIG_N_HDLC=m
+CONFIG_N_GSM=m
+CONFIG_NOZOMI=m
+# CONFIG_NULL_TTY is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_XEN=y
+CONFIG_HVC_XEN_FRONTEND=y
+# CONFIG_HVC_DCC is not set
+# CONFIG_RPMSG_TTY is not set
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
+CONFIG_TTY_PRINTK=m
+CONFIG_TTY_PRINTK_LEVEL=6
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_DMI_DECODE=y
+CONFIG_IPMI_PLAT_DATA=y
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+# CONFIG_IPMI_SSIF is not set
+# CONFIG_IPMI_IPMB is not set
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+# CONFIG_SSIF_IPMI_BMC is not set
+# CONFIG_IPMB_DEVICE_INTERFACE is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_HW_RANDOM_BA431 is not set
+CONFIG_HW_RANDOM_BCM2835=m
+CONFIG_HW_RANDOM_IPROC_RNG200=m
+CONFIG_HW_RANDOM_OMAP=m
+CONFIG_HW_RANDOM_VIRTIO=m
+CONFIG_HW_RANDOM_HISI=m
+CONFIG_HW_RANDOM_HISTB=m
+CONFIG_HW_RANDOM_XGENE=m
+CONFIG_HW_RANDOM_MESON=m
+CONFIG_HW_RANDOM_CAVIUM=m
+# CONFIG_HW_RANDOM_CCTRNG is not set
+# CONFIG_HW_RANDOM_XIPHERA is not set
+CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=m
+CONFIG_HW_RANDOM_CN10K=m
+# CONFIG_APPLICOM is not set
+CONFIG_DEVMEM=y
+CONFIG_DEVPORT=y
+CONFIG_TCG_TPM=m
+CONFIG_HW_RANDOM_TPM=y
+CONFIG_TCG_TIS_CORE=m
+CONFIG_TCG_TIS=m
+# CONFIG_TCG_TIS_I2C is not set
+# CONFIG_TCG_TIS_SYNQUACER is not set
+# CONFIG_TCG_TIS_I2C_CR50 is not set
+CONFIG_TCG_TIS_I2C_ATMEL=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
+CONFIG_TCG_TIS_I2C_NUVOTON=m
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_INFINEON=m
+CONFIG_TCG_XEN=m
+CONFIG_TCG_CRB=m
+# CONFIG_TCG_VTPM_PROXY is not set
+CONFIG_TCG_TIS_ST33ZP24=m
+CONFIG_TCG_TIS_ST33ZP24_I2C=m
+# CONFIG_XILLYBUS is not set
+# CONFIG_XILLYUSB is not set
+# end of Character devices
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_ACPI_I2C_OPREGION=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX=m
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_GPMUX is not set
+# CONFIG_I2C_MUX_LTC4306 is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MUX_REG is not set
+# CONFIG_I2C_DEMUX_PINCTRL is not set
+# CONFIG_I2C_MUX_MLXCPLD is not set
+# end of Multiplexer I2C Chip support
+
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_SMBUS=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+CONFIG_I2C_CCGX_UCSI=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD8111=m
+# CONFIG_I2C_AMD_MP2 is not set
+# CONFIG_I2C_HIX5HD2 is not set
+CONFIG_I2C_I801=m
+CONFIG_I2C_ISCH=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_NFORCE2=m
+# CONFIG_I2C_NVIDIA_GPU is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+
+#
+# ACPI drivers
+#
+CONFIG_I2C_SCMI=m
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_BCM2835 is not set
+CONFIG_I2C_BRCMSTB=y
+# CONFIG_I2C_CADENCE is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+CONFIG_I2C_DESIGNWARE_CORE=y
+# CONFIG_I2C_DESIGNWARE_SLAVE is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_I2C_DESIGNWARE_PCI=m
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_HISI is not set
+# CONFIG_I2C_IMX is not set
+# CONFIG_I2C_IMX_LPI2C is not set
+CONFIG_I2C_KEMPLD=m
+# CONFIG_I2C_MESON is not set
+# CONFIG_I2C_MV64XXX is not set
+# CONFIG_I2C_NOMADIK is not set
+CONFIG_I2C_OCORES=m
+# CONFIG_I2C_OMAP is not set
+CONFIG_I2C_PCA_PLATFORM=m
+# CONFIG_I2C_PXA is not set
+# CONFIG_I2C_QCOM_CCI is not set
+# CONFIG_I2C_QUP is not set
+# CONFIG_I2C_RIIC is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_RZV2M is not set
+# CONFIG_I2C_SH_MOBILE is not set
+CONFIG_I2C_SIMTEC=m
+# CONFIG_I2C_SYNQUACER is not set
+# CONFIG_I2C_TEGRA is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_THUNDERX is not set
+CONFIG_I2C_XILINX=m
+# CONFIG_I2C_XLP9XX is not set
+# CONFIG_I2C_RCAR is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_DIOLAN_U2C=m
+# CONFIG_I2C_CP2615 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PCI1XXXX is not set
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TAOS_EVM=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_I2C_VIPERBOARD=m
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_I2C_MLXCPLD=m
+# CONFIG_I2C_XGENE_SLIMPRO is not set
+# CONFIG_I2C_VIRTIO is not set
+# end of I2C Hardware Bus support
+
+CONFIG_I2C_STUB=m
+CONFIG_I2C_SLAVE=y
+CONFIG_I2C_SLAVE_EEPROM=m
+# CONFIG_I2C_SLAVE_TESTUNIT is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# end of I2C support
+
+# CONFIG_I3C is not set
+# CONFIG_SPI is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+CONFIG_PPS=y
+# CONFIG_PPS_DEBUG is not set
+
+#
+# PPS clients support
+#
+# CONFIG_PPS_CLIENT_KTIMER is not set
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PTP_1588_CLOCK_KVM=y
+# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
+# CONFIG_PTP_1588_CLOCK_IDTCM is not set
+# CONFIG_PTP_1588_CLOCK_MOCK is not set
+# end of PTP clock support
+
+CONFIG_PINCTRL=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_PINMUX=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+# CONFIG_DEBUG_PINCTRL is not set
+CONFIG_PINCTRL_AMD=y
+CONFIG_PINCTRL_AXP209=m
+# CONFIG_PINCTRL_CY8C95X0 is not set
+# CONFIG_PINCTRL_MCP23S08 is not set
+# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set
+# CONFIG_PINCTRL_OCELOT is not set
+CONFIG_PINCTRL_ROCKCHIP=y
+CONFIG_PINCTRL_SINGLE=y
+# CONFIG_PINCTRL_STMFX is not set
+# CONFIG_PINCTRL_SX150X is not set
+CONFIG_PINCTRL_BCM2835=y
+CONFIG_PINCTRL_IMX=y
+CONFIG_PINCTRL_IMX8MM=y
+CONFIG_PINCTRL_IMX8MN=y
+CONFIG_PINCTRL_IMX8MP=y
+CONFIG_PINCTRL_IMX8MQ=y
+# CONFIG_PINCTRL_IMX8ULP is not set
+# CONFIG_PINCTRL_IMXRT1050 is not set
+# CONFIG_PINCTRL_IMX93 is not set
+# CONFIG_PINCTRL_IMXRT1170 is not set
+CONFIG_PINCTRL_MESON=y
+CONFIG_PINCTRL_MESON_GXBB=y
+CONFIG_PINCTRL_MESON_GXL=y
+CONFIG_PINCTRL_MESON8_PMX=y
+CONFIG_PINCTRL_MESON_AXG=y
+CONFIG_PINCTRL_MESON_AXG_PMX=y
+CONFIG_PINCTRL_MESON_G12A=y
+CONFIG_PINCTRL_MESON_A1=y
+CONFIG_PINCTRL_MESON_S4=y
+CONFIG_PINCTRL_AMLOGIC_C3=y
+CONFIG_PINCTRL_MVEBU=y
+CONFIG_PINCTRL_ARMADA_AP806=y
+CONFIG_PINCTRL_ARMADA_CP110=y
+CONFIG_PINCTRL_AC5=y
+CONFIG_PINCTRL_ARMADA_37XX=y
+CONFIG_PINCTRL_MSM=y
+# CONFIG_PINCTRL_IPQ5018 is not set
+# CONFIG_PINCTRL_IPQ5332 is not set
+# CONFIG_PINCTRL_IPQ8074 is not set
+# CONFIG_PINCTRL_IPQ6018 is not set
+# CONFIG_PINCTRL_IPQ9574 is not set
+# CONFIG_PINCTRL_MDM9607 is not set
+CONFIG_PINCTRL_MSM8916=y
+# CONFIG_PINCTRL_MSM8953 is not set
+# CONFIG_PINCTRL_MSM8976 is not set
+# CONFIG_PINCTRL_MSM8994 is not set
+CONFIG_PINCTRL_MSM8996=y
+# CONFIG_PINCTRL_MSM8998 is not set
+# CONFIG_PINCTRL_QCM2290 is not set
+# CONFIG_PINCTRL_QCS404 is not set
+# CONFIG_PINCTRL_QDF2XXX is not set
+# CONFIG_PINCTRL_QDU1000 is not set
+# CONFIG_PINCTRL_SA8775P is not set
+# CONFIG_PINCTRL_SC7180 is not set
+# CONFIG_PINCTRL_SC7280 is not set
+# CONFIG_PINCTRL_SC8180X is not set
+# CONFIG_PINCTRL_SC8280XP is not set
+# CONFIG_PINCTRL_SDM660 is not set
+# CONFIG_PINCTRL_SDM670 is not set
+CONFIG_PINCTRL_SDM845=y
+# CONFIG_PINCTRL_SDX75 is not set
+# CONFIG_PINCTRL_SM6115 is not set
+# CONFIG_PINCTRL_SM6125 is not set
+# CONFIG_PINCTRL_SM6350 is not set
+# CONFIG_PINCTRL_SM6375 is not set
+# CONFIG_PINCTRL_SM7150 is not set
+# CONFIG_PINCTRL_SM8150 is not set
+# CONFIG_PINCTRL_SM8250 is not set
+# CONFIG_PINCTRL_SM8350 is not set
+# CONFIG_PINCTRL_SM8450 is not set
+# CONFIG_PINCTRL_SM8550 is not set
+CONFIG_PINCTRL_QCOM_SSBI_PMIC=y
+# CONFIG_PINCTRL_LPASS_LPI is not set
+
+#
+# Renesas pinctrl drivers
+#
+CONFIG_PINCTRL_RENESAS=y
+# end of Renesas pinctrl drivers
+
+CONFIG_PINCTRL_SUNXI=y
+# CONFIG_PINCTRL_SUN4I_A10 is not set
+# CONFIG_PINCTRL_SUN5I is not set
+# CONFIG_PINCTRL_SUN6I_A31 is not set
+# CONFIG_PINCTRL_SUN6I_A31_R is not set
+# CONFIG_PINCTRL_SUN8I_A23 is not set
+# CONFIG_PINCTRL_SUN8I_A33 is not set
+# CONFIG_PINCTRL_SUN8I_A83T is not set
+# CONFIG_PINCTRL_SUN8I_A83T_R is not set
+# CONFIG_PINCTRL_SUN8I_A23_R is not set
+# CONFIG_PINCTRL_SUN8I_H3 is not set
+CONFIG_PINCTRL_SUN8I_H3_R=y
+# CONFIG_PINCTRL_SUN8I_V3S is not set
+# CONFIG_PINCTRL_SUN9I_A80 is not set
+# CONFIG_PINCTRL_SUN9I_A80_R is not set
+# CONFIG_PINCTRL_SUN20I_D1 is not set
+CONFIG_PINCTRL_SUN50I_A64=y
+CONFIG_PINCTRL_SUN50I_A64_R=y
+CONFIG_PINCTRL_SUN50I_A100=y
+CONFIG_PINCTRL_SUN50I_A100_R=y
+CONFIG_PINCTRL_SUN50I_H5=y
+CONFIG_PINCTRL_SUN50I_H6=y
+CONFIG_PINCTRL_SUN50I_H6_R=y
+CONFIG_PINCTRL_SUN50I_H616=y
+CONFIG_PINCTRL_SUN50I_H616_R=y
+CONFIG_PINCTRL_TEGRA_XUSB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_FASTPATH_LIMIT=512
+CONFIG_OF_GPIO=y
+CONFIG_GPIO_ACPI=y
+CONFIG_GPIOLIB_IRQCHIP=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_CDEV_V1=y
+CONFIG_GPIO_GENERIC=y
+
+#
+# Memory mapped GPIO drivers
+#
+# CONFIG_GPIO_74XX_MMIO is not set
+# CONFIG_GPIO_ALTERA is not set
+# CONFIG_GPIO_AMDPT is not set
+CONFIG_GPIO_RASPBERRYPI_EXP=y
+# CONFIG_GPIO_CADENCE is not set
+CONFIG_GPIO_DAVINCI=y
+# CONFIG_GPIO_DWAPB is not set
+CONFIG_GPIO_EXAR=m
+# CONFIG_GPIO_FTGPIO010 is not set
+CONFIG_GPIO_GENERIC_PLATFORM=y
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_HISI is not set
+# CONFIG_GPIO_HLWD is not set
+# CONFIG_GPIO_LOGICVC is not set
+CONFIG_GPIO_MB86S7X=m
+CONFIG_GPIO_MPC8XXX=y
+CONFIG_GPIO_MVEBU=y
+CONFIG_GPIO_MXC=y
+CONFIG_GPIO_PL061=y
+CONFIG_GPIO_RCAR=m
+CONFIG_GPIO_ROCKCHIP=y
+# CONFIG_GPIO_SIFIVE is not set
+# CONFIG_GPIO_SYSCON is not set
+CONFIG_GPIO_TEGRA=y
+# CONFIG_GPIO_THUNDERX is not set
+CONFIG_GPIO_VF610=y
+CONFIG_GPIO_XGENE=y
+CONFIG_GPIO_XGENE_SB=m
+# CONFIG_GPIO_XILINX is not set
+CONFIG_GPIO_XLP=y
+# CONFIG_GPIO_AMD_FCH is not set
+# end of Memory mapped GPIO drivers
+
+#
+# I2C GPIO expanders
+#
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_FXL6408 is not set
+# CONFIG_GPIO_DS4520 is not set
+# CONFIG_GPIO_GW_PLD is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCA9570 is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_TPIC2810 is not set
+# end of I2C GPIO expanders
+
+#
+# MFD GPIO expanders
+#
+# CONFIG_GPIO_KEMPLD is not set
+# end of MFD GPIO expanders
+
+#
+# PCI GPIO expanders
+#
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_PCI_IDIO_16 is not set
+# CONFIG_GPIO_PCIE_IDIO_24 is not set
+# CONFIG_GPIO_RDC321X is not set
+# end of PCI GPIO expanders
+
+#
+# USB GPIO expanders
+#
+CONFIG_GPIO_VIPERBOARD=m
+# end of USB GPIO expanders
+
+#
+# Virtual GPIO drivers
+#
+# CONFIG_GPIO_AGGREGATOR is not set
+# CONFIG_GPIO_LATCH is not set
+# CONFIG_GPIO_MOCKUP is not set
+# CONFIG_GPIO_VIRTIO is not set
+# CONFIG_GPIO_SIM is not set
+# end of Virtual GPIO drivers
+
+CONFIG_W1=m
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+# CONFIG_W1_MASTER_MXC is not set
+CONFIG_W1_MASTER_GPIO=m
+# CONFIG_W1_MASTER_SGI is not set
+# end of 1-wire Bus Masters
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2405=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2408_READBACK=y
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2805=m
+# CONFIG_W1_SLAVE_DS2430 is not set
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+CONFIG_W1_SLAVE_DS2438=m
+# CONFIG_W1_SLAVE_DS250X is not set
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+# end of 1-wire Slaves
+
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMSTB is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_HISI is not set
+# CONFIG_POWER_RESET_LINKSTATION is not set
+# CONFIG_POWER_RESET_MSM is not set
+# CONFIG_POWER_RESET_ODROID_GO_ULTRA_POWEROFF is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_REGULATOR is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_VEXPRESS is not set
+# CONFIG_POWER_RESET_XGENE is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+# CONFIG_SYSCON_REBOOT_MODE is not set
+# CONFIG_NVMEM_REBOOT_MODE is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_POWER_SUPPLY_HWMON=y
+# CONFIG_IP5XXX_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_CHARGER_ADP5061 is not set
+# CONFIG_BATTERY_CW2015 is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SAMSUNG_SDI is not set
+CONFIG_BATTERY_SBS=m
+# CONFIG_CHARGER_SBS is not set
+# CONFIG_MANAGER_SBS is not set
+CONFIG_BATTERY_BQ27XXX=m
+# CONFIG_BATTERY_BQ27XXX_I2C is not set
+CONFIG_BATTERY_BQ27XXX_HDQ=m
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_MAX17042=m
+# CONFIG_BATTERY_MAX1721X is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_LT3651 is not set
+# CONFIG_CHARGER_LTC4162L is not set
+# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
+# CONFIG_CHARGER_MAX77976 is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24257 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ2515X is not set
+# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_BQ25980 is not set
+# CONFIG_CHARGER_BQ256XX is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_RT5033 is not set
+# CONFIG_CHARGER_RT9455 is not set
+# CONFIG_CHARGER_RT9467 is not set
+# CONFIG_CHARGER_RT9471 is not set
+# CONFIG_CHARGER_UCS1002 is not set
+# CONFIG_CHARGER_BD99954 is not set
+# CONFIG_BATTERY_UG3105 is not set
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+CONFIG_SENSORS_AD7414=m
+CONFIG_SENSORS_AD7418=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+# CONFIG_SENSORS_ADM1177 is not set
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_ADT7X10=m
+CONFIG_SENSORS_ADT7410=m
+CONFIG_SENSORS_ADT7411=m
+CONFIG_SENSORS_ADT7462=m
+CONFIG_SENSORS_ADT7470=m
+CONFIG_SENSORS_ADT7475=m
+# CONFIG_SENSORS_AHT10 is not set
+# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
+# CONFIG_SENSORS_AS370 is not set
+CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
+# CONFIG_SENSORS_ARM_SCMI is not set
+CONFIG_SENSORS_ARM_SCPI=m
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_CORSAIR_CPRO is not set
+# CONFIG_SENSORS_CORSAIR_PSU is not set
+CONFIG_SENSORS_DRIVETEMP=m
+CONFIG_SENSORS_DS620=m
+# CONFIG_SENSORS_DS1621 is not set
+CONFIG_SENSORS_I5K_AMB=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_F75375S=m
+CONFIG_SENSORS_FTSTEUTATES=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_G760A=m
+CONFIG_SENSORS_G762=m
+# CONFIG_SENSORS_GPIO_FAN is not set
+CONFIG_SENSORS_HIH6130=m
+# CONFIG_SENSORS_HS3001 is not set
+CONFIG_SENSORS_IBMAEM=m
+CONFIG_SENSORS_IBMPEX=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_POWR1220=m
+CONFIG_SENSORS_LINEAGE=m
+CONFIG_SENSORS_LTC2945=m
+# CONFIG_SENSORS_LTC2947_I2C is not set
+CONFIG_SENSORS_LTC2990=m
+# CONFIG_SENSORS_LTC2992 is not set
+CONFIG_SENSORS_LTC4151=m
+CONFIG_SENSORS_LTC4215=m
+CONFIG_SENSORS_LTC4222=m
+CONFIG_SENSORS_LTC4245=m
+CONFIG_SENSORS_LTC4260=m
+CONFIG_SENSORS_LTC4261=m
+# CONFIG_SENSORS_MAX127 is not set
+CONFIG_SENSORS_MAX16065=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_MAX1668=m
+CONFIG_SENSORS_MAX197=m
+# CONFIG_SENSORS_MAX31730 is not set
+# CONFIG_SENSORS_MAX31760 is not set
+# CONFIG_MAX31827 is not set
+# CONFIG_SENSORS_MAX6620 is not set
+CONFIG_SENSORS_MAX6621=m
+CONFIG_SENSORS_MAX6639=m
+CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_MAX6697=m
+CONFIG_SENSORS_MAX31790=m
+# CONFIG_SENSORS_MC34VR500 is not set
+CONFIG_SENSORS_MCP3021=m
+CONFIG_SENSORS_TC654=m
+# CONFIG_SENSORS_TPS23861 is not set
+CONFIG_SENSORS_MENF21BMC_HWMON=m
+# CONFIG_SENSORS_MR75203 is not set
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_LM95234=m
+CONFIG_SENSORS_LM95241=m
+CONFIG_SENSORS_LM95245=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_NCT6683=m
+CONFIG_SENSORS_NCT6775_CORE=m
+CONFIG_SENSORS_NCT6775=m
+# CONFIG_SENSORS_NCT6775_I2C is not set
+CONFIG_SENSORS_NCT7802=m
+CONFIG_SENSORS_NCT7904=m
+CONFIG_SENSORS_NPCM7XX=m
+# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
+# CONFIG_SENSORS_NZXT_SMART2 is not set
+# CONFIG_SENSORS_OCC_P8_I2C is not set
+CONFIG_SENSORS_PCF8591=m
+CONFIG_PMBUS=m
+CONFIG_SENSORS_PMBUS=m
+# CONFIG_SENSORS_ACBEL_FSG032 is not set
+# CONFIG_SENSORS_ADM1266 is not set
+CONFIG_SENSORS_ADM1275=m
+# CONFIG_SENSORS_BEL_PFE is not set
+# CONFIG_SENSORS_BPA_RS600 is not set
+# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set
+# CONFIG_SENSORS_FSP_3Y is not set
+CONFIG_SENSORS_IBM_CFFPS=m
+# CONFIG_SENSORS_DPS920AB is not set
+# CONFIG_SENSORS_INSPUR_IPSPS is not set
+CONFIG_SENSORS_IR35221=m
+# CONFIG_SENSORS_IR36021 is not set
+# CONFIG_SENSORS_IR38064 is not set
+# CONFIG_SENSORS_IRPS5401 is not set
+# CONFIG_SENSORS_ISL68137 is not set
+CONFIG_SENSORS_LM25066=m
+# CONFIG_SENSORS_LM25066_REGULATOR is not set
+# CONFIG_SENSORS_LT7182S is not set
+CONFIG_SENSORS_LTC2978=m
+CONFIG_SENSORS_LTC2978_REGULATOR=y
+CONFIG_SENSORS_LTC3815=m
+# CONFIG_SENSORS_MAX15301 is not set
+CONFIG_SENSORS_MAX16064=m
+# CONFIG_SENSORS_MAX16601 is not set
+# CONFIG_SENSORS_MAX20730 is not set
+CONFIG_SENSORS_MAX20751=m
+CONFIG_SENSORS_MAX31785=m
+CONFIG_SENSORS_MAX34440=m
+CONFIG_SENSORS_MAX8688=m
+# CONFIG_SENSORS_MP2888 is not set
+# CONFIG_SENSORS_MP2975 is not set
+# CONFIG_SENSORS_MP5023 is not set
+# CONFIG_SENSORS_MPQ7932 is not set
+# CONFIG_SENSORS_PIM4328 is not set
+# CONFIG_SENSORS_PLI1209BC is not set
+# CONFIG_SENSORS_PM6764TR is not set
+# CONFIG_SENSORS_PXE1610 is not set
+# CONFIG_SENSORS_Q54SJ108A2 is not set
+# CONFIG_SENSORS_STPDDC60 is not set
+# CONFIG_SENSORS_TDA38640 is not set
+CONFIG_SENSORS_TPS40422=m
+CONFIG_SENSORS_TPS53679=m
+# CONFIG_SENSORS_TPS546D24 is not set
+CONFIG_SENSORS_UCD9000=m
+CONFIG_SENSORS_UCD9200=m
+# CONFIG_SENSORS_XDPE152 is not set
+# CONFIG_SENSORS_XDPE122 is not set
+CONFIG_SENSORS_ZL6100=m
+# CONFIG_SENSORS_RASPBERRYPI_HWMON is not set
+# CONFIG_SENSORS_SBTSI is not set
+# CONFIG_SENSORS_SBRMI is not set
+CONFIG_SENSORS_SHT15=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+# CONFIG_SENSORS_SHT4x is not set
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_DME1737=m
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+# CONFIG_SENSORS_EMC2305 is not set
+CONFIG_SENSORS_EMC6W201=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_SMSC47M192=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SCH56XX_COMMON=m
+CONFIG_SENSORS_SCH5627=m
+CONFIG_SENSORS_SCH5636=m
+CONFIG_SENSORS_STTS751=m
+CONFIG_SENSORS_ADC128D818=m
+CONFIG_SENSORS_ADS7828=m
+CONFIG_SENSORS_AMC6821=m
+CONFIG_SENSORS_INA209=m
+CONFIG_SENSORS_INA2XX=m
+# CONFIG_SENSORS_INA238 is not set
+CONFIG_SENSORS_INA3221=m
+CONFIG_SENSORS_TC74=m
+CONFIG_SENSORS_THMC50=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_SENSORS_TMP103=m
+CONFIG_SENSORS_TMP108=m
+CONFIG_SENSORS_TMP401=m
+CONFIG_SENSORS_TMP421=m
+# CONFIG_SENSORS_TMP464 is not set
+# CONFIG_SENSORS_TMP513 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83773G=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83795=m
+# CONFIG_SENSORS_W83795_FANCTRL is not set
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83L786NG=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_SENSORS_XGENE=m
+
+#
+# ACPI drivers
+#
+CONFIG_SENSORS_ACPI_POWER=m
+CONFIG_THERMAL=y
+# CONFIG_THERMAL_NETLINK is not set
+# CONFIG_THERMAL_STATISTICS is not set
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+# CONFIG_CPU_THERMAL is not set
+# CONFIG_DEVFREQ_THERMAL is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_THERMAL_MMIO is not set
+CONFIG_HISI_THERMAL=m
+# CONFIG_IMX_THERMAL is not set
+# CONFIG_IMX8MM_THERMAL is not set
+CONFIG_K3_THERMAL=m
+CONFIG_QORIQ_THERMAL=m
+CONFIG_SUN8I_THERMAL=m
+CONFIG_ROCKCHIP_THERMAL=m
+# CONFIG_RCAR_THERMAL is not set
+# CONFIG_RCAR_GEN3_THERMAL is not set
+# CONFIG_RZG2L_THERMAL is not set
+CONFIG_ARMADA_THERMAL=m
+CONFIG_AMLOGIC_THERMAL=y
+
+#
+# Broadcom thermal drivers
+#
+CONFIG_BCM2711_THERMAL=m
+CONFIG_BCM2835_THERMAL=m
+# end of Broadcom thermal drivers
+
+#
+# NVIDIA Tegra thermal drivers
+#
+CONFIG_TEGRA_SOCTHERM=y
+# end of NVIDIA Tegra thermal drivers
+
+#
+# Qualcomm thermal drivers
+#
+# CONFIG_QCOM_LMH is not set
+# end of Qualcomm thermal drivers
+
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
+CONFIG_WATCHDOG_OPEN_TIMEOUT=0
+CONFIG_WATCHDOG_SYSFS=y
+# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
+
+#
+# Watchdog Pretimeout Governors
+#
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_MENF21BMC_WATCHDOG is not set
+# CONFIG_WDAT_WDT is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILINX_WINDOW_WATCHDOG is not set
+# CONFIG_ZIIRAVE_WATCHDOG is not set
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_ARM_SBSA_WATCHDOG=y
+# CONFIG_ARMADA_37XX_WATCHDOG is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_DW_WATCHDOG is not set
+CONFIG_K3_RTI_WATCHDOG=m
+CONFIG_SUNXI_WATCHDOG=m
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_IMX2_WDT is not set
+# CONFIG_IMX7ULP_WDT is not set
+# CONFIG_TEGRA_WATCHDOG is not set
+# CONFIG_QCOM_WDT is not set
+# CONFIG_MESON_GXBB_WATCHDOG is not set
+# CONFIG_MESON_WATCHDOG is not set
+# CONFIG_ARM_SMC_WATCHDOG is not set
+# CONFIG_RENESAS_WDT is not set
+# CONFIG_RENESAS_RZAWDT is not set
+# CONFIG_RENESAS_RZN1WDT is not set
+# CONFIG_RENESAS_RZG2LWDT is not set
+CONFIG_ALIM7101_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_HP_WATCHDOG=m
+CONFIG_KEMPLD_WDT=m
+CONFIG_MARVELL_GTI_WDT=y
+# CONFIG_BCM2835_WDT is not set
+# CONFIG_MEN_A21_WDT is not set
+CONFIG_XEN_WDT=m
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB=m
+CONFIG_SSB_SPROM=y
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_B43_PCI_BRIDGE=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+CONFIG_SSB_SDIOHOST=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_DRIVER_PCICORE=y
+# CONFIG_SSB_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+CONFIG_BCMA=m
+CONFIG_BCMA_BLOCKIO=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+CONFIG_BCMA_HOST_PCI=y
+# CONFIG_BCMA_HOST_SOC is not set
+CONFIG_BCMA_DRIVER_PCI=y
+# CONFIG_BCMA_DRIVER_GMAC_CMN is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+# CONFIG_BCMA_DEBUG is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_ACT8945A is not set
+# CONFIG_MFD_SUN4I_GPADC is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_SMPRO is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_ATMEL_FLEXCOM is not set
+# CONFIG_MFD_ATMEL_HLCDC is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_BD9571MWV is not set
+# CONFIG_MFD_AC100 is not set
+CONFIG_MFD_AXP20X=m
+CONFIG_MFD_AXP20X_I2C=m
+# CONFIG_MFD_AXP20X_RSB is not set
+# CONFIG_MFD_CS42L43_I2C is not set
+# CONFIG_MFD_MADERA is not set
+# CONFIG_MFD_MAX5970 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_GATEWORKS_GSC is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MP2629 is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_HI655X_PMIC is not set
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+# CONFIG_MFD_IQS62X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+CONFIG_MFD_KEMPLD=m
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77541 is not set
+# CONFIG_MFD_MAX77620 is not set
+# CONFIG_MFD_MAX77650 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77714 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MT6360 is not set
+# CONFIG_MFD_MT6370 is not set
+# CONFIG_MFD_MT6397 is not set
+CONFIG_MFD_MENF21BMC=m
+CONFIG_MFD_VIPERBOARD=m
+# CONFIG_MFD_NTXEC is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_QCOM_RPM is not set
+# CONFIG_MFD_SY7636A is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RT4831 is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RT5120 is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RK8XX_I2C is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SL28CPLD is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SKY81452 is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_SUN6I_PRCM is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_TI_LMU is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65086 is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TI_LP873X is not set
+# CONFIG_MFD_TI_LP87565 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS65219 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS6594_I2C is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TQMX86 is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_LOCHNAGAR is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_ROHM_BD718XX is not set
+# CONFIG_MFD_ROHM_BD71828 is not set
+# CONFIG_MFD_ROHM_BD957XMUF is not set
+# CONFIG_MFD_STPMIC1 is not set
+# CONFIG_MFD_STMFX is not set
+# CONFIG_MFD_ATC260X_I2C is not set
+# CONFIG_MFD_KHADAS_MCU is not set
+# CONFIG_MFD_QCOM_PM8008 is not set
+CONFIG_MFD_VEXPRESS_SYSREG=y
+# CONFIG_RAVE_SP_CORE is not set
+# CONFIG_MFD_RSMU_I2C is not set
+# end of Multifunction device drivers
+
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_REGULATOR_88PG86X=m
+CONFIG_REGULATOR_ACT8865=m
+CONFIG_REGULATOR_AD5398=m
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_ARM_SCMI is not set
+# CONFIG_REGULATOR_AW37503 is not set
+CONFIG_REGULATOR_AXP20X=m
+# CONFIG_REGULATOR_DA9121 is not set
+CONFIG_REGULATOR_DA9210=m
+CONFIG_REGULATOR_DA9211=m
+CONFIG_REGULATOR_FAN53555=m
+# CONFIG_REGULATOR_FAN53880 is not set
+CONFIG_REGULATOR_GPIO=m
+CONFIG_REGULATOR_ISL9305=m
+CONFIG_REGULATOR_ISL6271A=m
+CONFIG_REGULATOR_LP3971=m
+CONFIG_REGULATOR_LP3972=m
+CONFIG_REGULATOR_LP872X=m
+CONFIG_REGULATOR_LP8755=m
+CONFIG_REGULATOR_LTC3589=m
+CONFIG_REGULATOR_LTC3676=m
+CONFIG_REGULATOR_MAX1586=m
+# CONFIG_REGULATOR_MAX77857 is not set
+CONFIG_REGULATOR_MAX8649=m
+CONFIG_REGULATOR_MAX8660=m
+# CONFIG_REGULATOR_MAX8893 is not set
+CONFIG_REGULATOR_MAX8952=m
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_MAX20086 is not set
+# CONFIG_REGULATOR_MAX20411 is not set
+# CONFIG_REGULATOR_MAX77826 is not set
+# CONFIG_REGULATOR_MCP16502 is not set
+# CONFIG_REGULATOR_MP5416 is not set
+# CONFIG_REGULATOR_MP8859 is not set
+# CONFIG_REGULATOR_MP886X is not set
+# CONFIG_REGULATOR_MPQ7920 is not set
+CONFIG_REGULATOR_MT6311=m
+# CONFIG_REGULATOR_PCA9450 is not set
+# CONFIG_REGULATOR_PF8X00 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+CONFIG_REGULATOR_PV88060=m
+CONFIG_REGULATOR_PV88080=m
+CONFIG_REGULATOR_PV88090=m
+# CONFIG_REGULATOR_QCOM_REFGEN is not set
+# CONFIG_REGULATOR_RAA215300 is not set
+# CONFIG_REGULATOR_RT4801 is not set
+# CONFIG_REGULATOR_RT4803 is not set
+# CONFIG_REGULATOR_RT5190A is not set
+# CONFIG_REGULATOR_RT5739 is not set
+# CONFIG_REGULATOR_RT5759 is not set
+# CONFIG_REGULATOR_RT6160 is not set
+# CONFIG_REGULATOR_RT6190 is not set
+# CONFIG_REGULATOR_RT6245 is not set
+# CONFIG_REGULATOR_RTQ2134 is not set
+# CONFIG_REGULATOR_RTMV20 is not set
+# CONFIG_REGULATOR_RTQ6752 is not set
+# CONFIG_REGULATOR_RTQ2208 is not set
+# CONFIG_REGULATOR_SLG51000 is not set
+# CONFIG_REGULATOR_SY8106A is not set
+# CONFIG_REGULATOR_SY8824X is not set
+# CONFIG_REGULATOR_SY8827N is not set
+CONFIG_REGULATOR_TPS51632=m
+CONFIG_REGULATOR_TPS62360=m
+# CONFIG_REGULATOR_TPS6286X is not set
+# CONFIG_REGULATOR_TPS6287X is not set
+CONFIG_REGULATOR_TPS65023=m
+CONFIG_REGULATOR_TPS6507X=m
+CONFIG_REGULATOR_TPS65132=m
+# CONFIG_REGULATOR_VCTRL is not set
+# CONFIG_REGULATOR_VEXPRESS is not set
+# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set
+# CONFIG_RC_CORE is not set
+
+#
+# CEC support
+#
+# CONFIG_MEDIA_CEC_SUPPORT is not set
+# end of CEC support
+
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_APERTURE_HELPERS=y
+CONFIG_VIDEO_CMDLINE=y
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_PANEL is not set
+# CONFIG_TEGRA_HOST1X is not set
+CONFIG_DRM=y
+# CONFIG_DRM_DEBUG_MM is not set
+CONFIG_DRM_KMS_HELPER=y
+# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
+# CONFIG_DRM_DEBUG_MODESET_LOCK is not set
+CONFIG_DRM_FBDEV_EMULATION=y
+CONFIG_DRM_FBDEV_OVERALLOC=100
+# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
+CONFIG_DRM_TTM=y
+CONFIG_DRM_TTM_HELPER=y
+CONFIG_DRM_GEM_SHMEM_HELPER=y
+
+#
+# I2C encoder or helper chips
+#
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
+# CONFIG_DRM_I2C_NXP_TDA9950 is not set
+# end of I2C encoder or helper chips
+
+#
+# ARM devices
+#
+# CONFIG_DRM_HDLCD is not set
+# CONFIG_DRM_MALI_DISPLAY is not set
+# CONFIG_DRM_KOMEDA is not set
+# end of ARM devices
+
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_AMDGPU is not set
+# CONFIG_DRM_NOUVEAU is not set
+# CONFIG_DRM_VGEM is not set
+# CONFIG_DRM_VKMS is not set
+# CONFIG_DRM_ROCKCHIP is not set
+# CONFIG_DRM_VMWGFX is not set
+# CONFIG_DRM_UDL is not set
+# CONFIG_DRM_AST is not set
+# CONFIG_DRM_MGAG200 is not set
+# CONFIG_DRM_RCAR_DU is not set
+# CONFIG_DRM_RZG2L_MIPI_DSI is not set
+# CONFIG_DRM_SHMOBILE is not set
+# CONFIG_DRM_SUN4I is not set
+CONFIG_DRM_QXL=y
+CONFIG_DRM_VIRTIO_GPU=y
+CONFIG_DRM_VIRTIO_GPU_KMS=y
+# CONFIG_DRM_MSM is not set
+# CONFIG_DRM_TEGRA is not set
+CONFIG_DRM_PANEL=y
+
+#
+# Display Panels
+#
+# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
+# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
+# end of Display Panels
+
+CONFIG_DRM_BRIDGE=y
+CONFIG_DRM_PANEL_BRIDGE=y
+
+#
+# Display Interface Bridges
+#
+# CONFIG_DRM_CHIPONE_ICN6211 is not set
+# CONFIG_DRM_CHRONTEL_CH7033 is not set
+# CONFIG_DRM_DISPLAY_CONNECTOR is not set
+# CONFIG_DRM_FSL_LDB is not set
+# CONFIG_DRM_ITE_IT6505 is not set
+# CONFIG_DRM_LONTIUM_LT8912B is not set
+# CONFIG_DRM_LONTIUM_LT9211 is not set
+# CONFIG_DRM_LONTIUM_LT9611 is not set
+# CONFIG_DRM_LONTIUM_LT9611UXC is not set
+# CONFIG_DRM_ITE_IT66121 is not set
+# CONFIG_DRM_LVDS_CODEC is not set
+# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
+# CONFIG_DRM_NWL_MIPI_DSI is not set
+# CONFIG_DRM_NXP_PTN3460 is not set
+# CONFIG_DRM_PARADE_PS8622 is not set
+# CONFIG_DRM_PARADE_PS8640 is not set
+# CONFIG_DRM_SAMSUNG_DSIM is not set
+# CONFIG_DRM_SIL_SII8620 is not set
+# CONFIG_DRM_SII902X is not set
+# CONFIG_DRM_SII9234 is not set
+# CONFIG_DRM_SIMPLE_BRIDGE is not set
+# CONFIG_DRM_THINE_THC63LVD1024 is not set
+# CONFIG_DRM_TOSHIBA_TC358762 is not set
+# CONFIG_DRM_TOSHIBA_TC358764 is not set
+# CONFIG_DRM_TOSHIBA_TC358767 is not set
+# CONFIG_DRM_TOSHIBA_TC358768 is not set
+# CONFIG_DRM_TOSHIBA_TC358775 is not set
+# CONFIG_DRM_TI_DLPC3433 is not set
+# CONFIG_DRM_TI_TFP410 is not set
+# CONFIG_DRM_TI_SN65DSI83 is not set
+# CONFIG_DRM_TI_SN65DSI86 is not set
+# CONFIG_DRM_TI_TPD12S015 is not set
+# CONFIG_DRM_ANALOGIX_ANX6345 is not set
+# CONFIG_DRM_ANALOGIX_ANX78XX is not set
+# CONFIG_DRM_ANALOGIX_ANX7625 is not set
+# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_CDNS_DSI is not set
+# CONFIG_DRM_CDNS_MHDP8546 is not set
+# CONFIG_DRM_IMX8QM_LDB is not set
+# CONFIG_DRM_IMX8QXP_LDB is not set
+# CONFIG_DRM_IMX8QXP_PIXEL_COMBINER is not set
+# CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI is not set
+# end of Display Interface Bridges
+
+# CONFIG_DRM_IMX_DCSS is not set
+# CONFIG_DRM_IMX_LCDC is not set
+# CONFIG_DRM_V3D is not set
+# CONFIG_DRM_LOONGSON is not set
+# CONFIG_DRM_ETNAVIV is not set
+# CONFIG_DRM_HISI_HIBMC is not set
+# CONFIG_DRM_HISI_KIRIN is not set
+# CONFIG_DRM_LOGICVC is not set
+# CONFIG_DRM_MXSFB is not set
+# CONFIG_DRM_IMX_LCDIF is not set
+# CONFIG_DRM_MESON is not set
+# CONFIG_DRM_ARCPGU is not set
+# CONFIG_DRM_BOCHS is not set
+# CONFIG_DRM_CIRRUS_QEMU is not set
+# CONFIG_DRM_GM12U320 is not set
+CONFIG_DRM_SIMPLEDRM=y
+# CONFIG_DRM_PL111 is not set
+# CONFIG_DRM_XEN_FRONTEND is not set
+# CONFIG_DRM_LIMA is not set
+# CONFIG_DRM_PANFROST is not set
+# CONFIG_DRM_TIDSS is not set
+# CONFIG_DRM_GUD is not set
+# CONFIG_DRM_SSD130X is not set
+# CONFIG_DRM_HYPERV is not set
+# CONFIG_DRM_LEGACY is not set
+CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_IMX is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_UVESA is not set
+CONFIG_FB_EFI=y
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_SH_MOBILE_LCDC is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_XEN_FBDEV_FRONTEND is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_HYPERV is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SM712 is not set
+CONFIG_FB_CORE=y
+CONFIG_FB_NOTIFY=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_DEVICE=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_IOMEM_HELPERS=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# end of Frame buffer Devices
+
+#
+# Backlight & LCD device support
+#
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+# end of Backlight & LCD device support
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
+# end of Console display driver support
+
+# CONFIG_LOGO is not set
+# end of Graphics support
+
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=m
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACCUTOUCH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_ASUS is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_BIGBEN_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_COUGAR is not set
+# CONFIG_HID_MACALLY is not set
+# CONFIG_HID_CMEDIA is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CREATIVE_SB0540 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELAN is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EVISION is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_FT260 is not set
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_GLORIOUS is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_GOOGLE_STADIA_FF is not set
+# CONFIG_HID_VIVALDI is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_VIEWSONIC is not set
+# CONFIG_HID_VRC2 is not set
+# CONFIG_HID_XIAOMI is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_ITE is not set
+# CONFIG_HID_JABRA is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LED is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LETSKETCH is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MALTRON is not set
+# CONFIG_HID_MAYFLASH is not set
+# CONFIG_HID_MEGAWORLD_FF is not set
+# CONFIG_HID_REDRAGON is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NINTENDO is not set
+# CONFIG_HID_NTI is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PXRC is not set
+# CONFIG_HID_RAZER is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_RETRODE is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SEMITEK is not set
+# CONFIG_HID_SIGMAMICRO is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEAM is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_HYPERV_MOUSE is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TOPRE is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_UDRAW_PS3 is not set
+# CONFIG_HID_U2FZERO is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_ALPS is not set
+# CONFIG_HID_MCP2221 is not set
+# end of Special HID drivers
+
+#
+# HID-BPF support
+#
+# end of HID-BPF support
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# end of USB HID Boot Protocol drivers
+# end of USB HID support
+
+CONFIG_I2C_HID=m
+# CONFIG_I2C_HID_ACPI is not set
+# CONFIG_I2C_HID_OF is not set
+# CONFIG_I2C_HID_OF_ELAN is not set
+# CONFIG_I2C_HID_OF_GOODIX is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_ULPI_BUS is not set
+# CONFIG_USB_CONN_GPIO is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+CONFIG_USB_PCI=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_FEW_INIT_RETRIES is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_PRODUCTLIST is not set
+# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
+# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
+CONFIG_USB_AUTOSUSPEND_DELAY=2
+# CONFIG_USB_MON is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_XHCI_HCD=m
+# CONFIG_USB_XHCI_DBGCAP is not set
+CONFIG_USB_XHCI_PCI=m
+# CONFIG_USB_XHCI_PCI_RENESAS is not set
+# CONFIG_USB_XHCI_PLATFORM is not set
+# CONFIG_USB_XHCI_MVEBU is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_PCI=m
+# CONFIG_USB_EHCI_FSL is not set
+CONFIG_USB_EHCI_HCD_ORION=m
+# CONFIG_USB_EHCI_TEGRA is not set
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PCI=m
+# CONFIG_USB_OHCI_HCD_SSB is not set
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+# CONFIG_USB_SL811_HCD_ISO is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_BCMA is not set
+# CONFIG_USB_HCD_SSB is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_XEN_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_UAS is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+
+#
+# USB dual-mode controller drivers
+#
+# CONFIG_USB_CDNS_SUPPORT is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_ISP1760 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_F8153X=m
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+CONFIG_USB_SERIAL_IUU=m
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_METRO is not set
+CONFIG_USB_SERIAL_MOS7720=m
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MXUPORT=m
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_SYMBOL is not set
+CONFIG_USB_SERIAL_TI=m
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_OPTION=m
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_UPD78F0730=m
+# CONFIG_USB_SERIAL_XR is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_QCOM_EUD is not set
+# CONFIG_APPLE_MFI_FASTCHARGE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_EZUSB_FX2=m
+# CONFIG_USB_HUB_USB251XB is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSIC_USB4604 is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_CHAOSKEY is not set
+# CONFIG_USB_ONBOARD_HUB is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_MXS_PHY is not set
+# CONFIG_USB_TEGRA_PHY is not set
+# CONFIG_USB_ULPI is not set
+# end of USB Physical Layer drivers
+
+# CONFIG_USB_GADGET is not set
+# CONFIG_TYPEC is not set
+# CONFIG_USB_ROLE_SWITCH is not set
+CONFIG_MMC=m
+CONFIG_PWRSEQ_EMMC=m
+# CONFIG_PWRSEQ_SD8787 is not set
+CONFIG_PWRSEQ_SIMPLE=m
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_MINORS=256
+CONFIG_SDIO_UART=m
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_ARMMMCI is not set
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_RICOH_MMC=y
+CONFIG_MMC_SDHCI_ACPI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
+# CONFIG_MMC_SDHCI_OF_AT91 is not set
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
+# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set
+# CONFIG_MMC_SDHCI_CADENCE is not set
+# CONFIG_MMC_SDHCI_ESDHC_IMX is not set
+# CONFIG_MMC_SDHCI_TEGRA is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+CONFIG_MMC_SDHCI_F_SDH30=m
+# CONFIG_MMC_SDHCI_MILBEAUT is not set
+# CONFIG_MMC_SDHCI_IPROC is not set
+# CONFIG_MMC_MESON_GX is not set
+# CONFIG_MMC_MESON_MX_SDIO is not set
+# CONFIG_MMC_SDHCI_MSM is not set
+# CONFIG_MMC_MXC is not set
+CONFIG_MMC_TIFM_SD=m
+# CONFIG_MMC_SDHI is not set
+CONFIG_MMC_CB710=m
+CONFIG_MMC_VIA_SDMMC=m
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_SH_MMCIF is not set
+CONFIG_MMC_VUB300=m
+CONFIG_MMC_USHC=m
+CONFIG_MMC_USDHI6ROL0=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
+# CONFIG_MMC_SUNXI is not set
+CONFIG_MMC_CQHCI=m
+# CONFIG_MMC_HSQ is not set
+# CONFIG_MMC_TOSHIBA_PCI is not set
+# CONFIG_MMC_BCM2835 is not set
+CONFIG_MMC_MTK=m
+CONFIG_MMC_SDHCI_XENON=m
+# CONFIG_MMC_SDHCI_AM654 is not set
+CONFIG_SCSI_UFSHCD=m
+# CONFIG_SCSI_UFS_BSG is not set
+# CONFIG_SCSI_UFS_HWMON is not set
+CONFIG_SCSI_UFSHCD_PCI=m
+# CONFIG_SCSI_UFS_DWC_TC_PCI is not set
+# CONFIG_SCSI_UFSHCD_PLATFORM is not set
+# CONFIG_SCSI_UFS_TI_J721E is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_AN30259A is not set
+# CONFIG_LEDS_AW200XX is not set
+# CONFIG_LEDS_AW2013 is not set
+# CONFIG_LEDS_BCM6328 is not set
+# CONFIG_LEDS_BCM6358 is not set
+CONFIG_LEDS_LM3530=m
+# CONFIG_LEDS_LM3532 is not set
+CONFIG_LEDS_LM3642=m
+# CONFIG_LEDS_LM3692X is not set
+CONFIG_LEDS_PCA9532=m
+# CONFIG_LEDS_PCA9532_GPIO is not set
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_LP3952=m
+# CONFIG_LEDS_LP50XX is not set
+# CONFIG_LEDS_LP55XX_COMMON is not set
+# CONFIG_LEDS_LP8860 is not set
+CONFIG_LEDS_PCA955X=m
+# CONFIG_LEDS_PCA955X_GPIO is not set
+CONFIG_LEDS_PCA963X=m
+# CONFIG_LEDS_PCA995X is not set
+CONFIG_LEDS_REGULATOR=m
+# CONFIG_LEDS_BD2606MVV is not set
+CONFIG_LEDS_BD2802=m
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TCA6507=m
+CONFIG_LEDS_TLC591XX=m
+CONFIG_LEDS_LM355x=m
+CONFIG_LEDS_MENF21BMC=m
+# CONFIG_LEDS_IS31FL319X is not set
+# CONFIG_LEDS_IS31FL32XX is not set
+
+#
+# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
+#
+CONFIG_LEDS_BLINKM=m
+# CONFIG_LEDS_SYSCON is not set
+CONFIG_LEDS_MLXREG=m
+# CONFIG_LEDS_USER is not set
+# CONFIG_LEDS_LM3697 is not set
+
+#
+# Flash and Torch LED drivers
+#
+# CONFIG_LEDS_AAT1290 is not set
+CONFIG_LEDS_AS3645A=m
+# CONFIG_LEDS_KTD2692 is not set
+CONFIG_LEDS_LM3601X=m
+# CONFIG_LEDS_RT4505 is not set
+# CONFIG_LEDS_RT8515 is not set
+# CONFIG_LEDS_SGM3140 is not set
+
+#
+# RGB LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_ACTIVITY=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+# CONFIG_LEDS_TRIGGER_PATTERN is not set
+# CONFIG_LEDS_TRIGGER_AUDIO is not set
+# CONFIG_LEDS_TRIGGER_TTY is not set
+
+#
+# Simple LED drivers
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_INFINIBAND=m
+# CONFIG_INFINIBAND_USER_MAD is not set
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MEM=y
+CONFIG_INFINIBAND_ON_DEMAND_PAGING=y
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y
+CONFIG_INFINIBAND_VIRT_DMA=y
+# CONFIG_INFINIBAND_BNXT_RE is not set
+# CONFIG_INFINIBAND_CXGB4 is not set
+# CONFIG_INFINIBAND_EFA is not set
+# CONFIG_INFINIBAND_ERDMA is not set
+# CONFIG_INFINIBAND_IRDMA is not set
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_MLX5_INFINIBAND=m
+# CONFIG_INFINIBAND_MTHCA is not set
+# CONFIG_INFINIBAND_OCRDMA is not set
+# CONFIG_INFINIBAND_QEDR is not set
+# CONFIG_INFINIBAND_VMWARE_PVRDMA is not set
+# CONFIG_RDMA_RXE is not set
+# CONFIG_RDMA_SIW is not set
+# CONFIG_INFINIBAND_IPOIB is not set
+# CONFIG_INFINIBAND_SRP is not set
+# CONFIG_INFINIBAND_ISER is not set
+# CONFIG_INFINIBAND_RTRS_CLIENT is not set
+# CONFIG_INFINIBAND_RTRS_SERVER is not set
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EDAC=y
+CONFIG_EDAC_LEGACY_SYSFS=y
+# CONFIG_EDAC_DEBUG is not set
+# CONFIG_EDAC_GHES is not set
+# CONFIG_EDAC_LAYERSCAPE is not set
+# CONFIG_EDAC_THUNDERX is not set
+# CONFIG_EDAC_SYNOPSYS is not set
+# CONFIG_EDAC_XGENE is not set
+# CONFIG_EDAC_DMC520 is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+CONFIG_RTC_NVMEM=y
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABEOZ9 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_NCT3018Y is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12026 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF85363 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8010 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3028 is not set
+# CONFIG_RTC_DRV_RV3032 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+# CONFIG_RTC_DRV_SD3078 is not set
+
+#
+# SPI RTC drivers
+#
+CONFIG_RTC_I2C_AND_SPI=y
+
+#
+# SPI and I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX6110 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_EFI is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_ZYNQMP is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_IMXDI is not set
+# CONFIG_RTC_DRV_FSL_FTM_ALARM is not set
+CONFIG_RTC_DRV_MESON_VRTC=m
+# CONFIG_RTC_DRV_SH is not set
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_SUN6I is not set
+# CONFIG_RTC_DRV_MV is not set
+# CONFIG_RTC_DRV_ARMADA38X is not set
+# CONFIG_RTC_DRV_CADENCE is not set
+# CONFIG_RTC_DRV_FTRTC010 is not set
+# CONFIG_RTC_DRV_TEGRA is not set
+# CONFIG_RTC_DRV_MXC is not set
+# CONFIG_RTC_DRV_MXC_V2 is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_BBNSM is not set
+# CONFIG_RTC_DRV_XGENE is not set
+# CONFIG_RTC_DRV_R7301 is not set
+# CONFIG_RTC_DRV_TI_K3 is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_GOLDFISH is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DMA_ACPI=y
+CONFIG_DMA_OF=y
+# CONFIG_ALTERA_MSGDMA is not set
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_BCM_SBA_RAID is not set
+CONFIG_DMA_BCM2835=y
+CONFIG_DMA_SUN6I=m
+# CONFIG_DW_AXI_DMAC is not set
+CONFIG_FSL_EDMA=m
+CONFIG_FSL_QDMA=m
+# CONFIG_HISI_DMA is not set
+# CONFIG_IMX_DMA is not set
+CONFIG_IMX_SDMA=m
+# CONFIG_INTEL_IDMA64 is not set
+CONFIG_K3_DMA=m
+CONFIG_MV_XOR=y
+CONFIG_MV_XOR_V2=y
+# CONFIG_MXS_DMA is not set
+CONFIG_PL330_DMA=m
+# CONFIG_PLX_DMA is not set
+# CONFIG_TEGRA186_GPC_DMA is not set
+CONFIG_TEGRA20_APB_DMA=y
+CONFIG_XGENE_DMA=m
+# CONFIG_XILINX_DMA is not set
+# CONFIG_XILINX_XDMA is not set
+# CONFIG_XILINX_ZYNQMP_DMA is not set
+# CONFIG_XILINX_ZYNQMP_DPDMA is not set
+CONFIG_QCOM_BAM_DMA=m
+# CONFIG_QCOM_GPI_DMA is not set
+CONFIG_QCOM_HIDMA_MGMT=m
+CONFIG_QCOM_HIDMA=m
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_DMAC_PCI is not set
+# CONFIG_DW_EDMA is not set
+# CONFIG_SF_PDMA is not set
+# CONFIG_RCAR_DMAC is not set
+# CONFIG_RENESAS_USB_DMAC is not set
+CONFIG_TI_K3_UDMA=y
+CONFIG_TI_K3_UDMA_GLUE_LAYER=y
+CONFIG_TI_K3_PSIL=y
+
+#
+# DMA Clients
+#
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+CONFIG_DMA_ENGINE_RAID=y
+
+#
+# DMABUF options
+#
+CONFIG_SYNC_FILE=y
+# CONFIG_SW_SYNC is not set
+# CONFIG_UDMABUF is not set
+# CONFIG_DMABUF_MOVE_NOTIFY is not set
+# CONFIG_DMABUF_DEBUG is not set
+# CONFIG_DMABUF_SELFTESTS is not set
+# CONFIG_DMABUF_HEAPS is not set
+# CONFIG_DMABUF_SYSFS_STATS is not set
+# end of DMABUF options
+
+CONFIG_UIO=m
+# CONFIG_UIO_CIF is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_DMEM_GENIRQ is not set
+# CONFIG_UIO_AEC is not set
+# CONFIG_UIO_SERCOS3 is not set
+CONFIG_UIO_PCI_GENERIC=m
+# CONFIG_UIO_NETX is not set
+# CONFIG_UIO_PRUSS is not set
+# CONFIG_UIO_MF624 is not set
+CONFIG_UIO_HV_GENERIC=m
+CONFIG_VFIO=m
+CONFIG_VFIO_GROUP=y
+CONFIG_VFIO_CONTAINER=y
+CONFIG_VFIO_IOMMU_TYPE1=m
+CONFIG_VFIO_NOIOMMU=y
+CONFIG_VFIO_VIRQFD=y
+
+#
+# VFIO support for PCI devices
+#
+CONFIG_VFIO_PCI_CORE=m
+CONFIG_VFIO_PCI_MMAP=y
+CONFIG_VFIO_PCI_INTX=y
+CONFIG_VFIO_PCI=m
+# CONFIG_MLX5_VFIO_PCI is not set
+# end of VFIO support for PCI devices
+
+#
+# VFIO support for platform devices
+#
+# CONFIG_VFIO_PLATFORM is not set
+# CONFIG_VFIO_AMBA is not set
+# end of VFIO support for platform devices
+
+#
+# VFIO support for FSL_MC bus devices
+#
+CONFIG_VFIO_FSL_MC=m
+# end of VFIO support for FSL_MC bus devices
+
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VMGENID=y
+# CONFIG_NITRO_ENCLAVES is not set
+CONFIG_VIRTIO_ANCHOR=y
+CONFIG_VIRTIO=m
+CONFIG_VIRTIO_PCI_LIB=m
+CONFIG_VIRTIO_PCI_LIB_LEGACY=m
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_PCI=m
+CONFIG_VIRTIO_PCI_LEGACY=y
+# CONFIG_VIRTIO_PMEM is not set
+CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_MEM=m
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=m
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VIRTIO_VDPA=m
+CONFIG_VDPA=m
+CONFIG_VHOST_VDPA=m
+CONFIG_VHOST_IOTLB=m
+CONFIG_VHOST_TASK=y
+CONFIG_VHOST=m
+CONFIG_VHOST_MENU=y
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_VSOCK=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_HYPERV=m
+CONFIG_HYPERV_UTILS=m
+CONFIG_HYPERV_BALLOON=m
+# end of Microsoft Hyper-V guest support
+
+#
+# Xen driver support
+#
+CONFIG_XEN_BALLOON=y
+CONFIG_XEN_BALLOON_MEMORY_HOTPLUG=y
+CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
+CONFIG_XEN_DEV_EVTCHN=m
+CONFIG_XEN_BACKEND=y
+CONFIG_XENFS=m
+CONFIG_XEN_COMPAT_XENFS=y
+CONFIG_XEN_SYS_HYPERVISOR=y
+CONFIG_XEN_XENBUS_FRONTEND=y
+CONFIG_XEN_GNTDEV=m
+CONFIG_XEN_GRANT_DEV_ALLOC=m
+# CONFIG_XEN_GRANT_DMA_ALLOC is not set
+CONFIG_SWIOTLB_XEN=y
+CONFIG_XEN_PCI_STUB=y
+CONFIG_XEN_PCIDEV_STUB=m
+# CONFIG_XEN_PVCALLS_FRONTEND is not set
+# CONFIG_XEN_PVCALLS_BACKEND is not set
+CONFIG_XEN_PRIVCMD=m
+CONFIG_XEN_EFI=y
+CONFIG_XEN_AUTO_XLATE=y
+# CONFIG_XEN_VIRTIO is not set
+# end of Xen driver support
+
+# CONFIG_GREYBUS is not set
+# CONFIG_COMEDI is not set
+# CONFIG_STAGING is not set
+# CONFIG_GOLDFISH is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_MELLANOX_PLATFORM is not set
+CONFIG_SURFACE_PLATFORMS=y
+# CONFIG_SURFACE_3_POWER_OPREGION is not set
+# CONFIG_SURFACE_GPE is not set
+# CONFIG_SURFACE_HOTPLUG is not set
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+# CONFIG_SURFACE_AGGREGATOR is not set
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Clock driver for ARM Reference designs
+#
+# CONFIG_CLK_ICST is not set
+# CONFIG_CLK_SP810 is not set
+CONFIG_CLK_VEXPRESS_OSC=y
+# end of Clock driver for ARM Reference designs
+
+# CONFIG_COMMON_CLK_MAX9485 is not set
+CONFIG_COMMON_CLK_SCMI=y
+CONFIG_COMMON_CLK_SCPI=m
+CONFIG_COMMON_CLK_SI5341=y
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI514 is not set
+# CONFIG_COMMON_CLK_SI544 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_CDCE925 is not set
+# CONFIG_COMMON_CLK_CS2000_CP is not set
+CONFIG_COMMON_CLK_FSL_FLEXSPI=m
+CONFIG_COMMON_CLK_FSL_SAI=y
+# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
+CONFIG_CLK_QORIQ=y
+CONFIG_CLK_LS1028A_PLLDIG=y
+CONFIG_COMMON_CLK_XGENE=y
+# CONFIG_COMMON_CLK_RS9_PCIE is not set
+# CONFIG_COMMON_CLK_SI521XX is not set
+# CONFIG_COMMON_CLK_VC3 is not set
+# CONFIG_COMMON_CLK_VC5 is not set
+# CONFIG_COMMON_CLK_VC7 is not set
+# CONFIG_COMMON_CLK_FIXED_MMIO is not set
+CONFIG_CLK_BCM2711_DVP=y
+CONFIG_CLK_BCM2835=y
+CONFIG_CLK_RASPBERRYPI=y
+CONFIG_COMMON_CLK_HI3516CV300=y
+CONFIG_COMMON_CLK_HI3519=y
+CONFIG_COMMON_CLK_HI3559A=y
+CONFIG_COMMON_CLK_HI3660=y
+CONFIG_COMMON_CLK_HI3670=y
+CONFIG_COMMON_CLK_HI3798CV200=y
+CONFIG_COMMON_CLK_HI6220=y
+CONFIG_RESET_HISI=y
+CONFIG_STUB_CLK_HI6220=y
+CONFIG_STUB_CLK_HI3660=y
+CONFIG_MXC_CLK=y
+CONFIG_CLK_IMX8MM=y
+CONFIG_CLK_IMX8MN=y
+CONFIG_CLK_IMX8MP=y
+CONFIG_CLK_IMX8MQ=y
+# CONFIG_CLK_IMX8ULP is not set
+# CONFIG_CLK_IMX93 is not set
+CONFIG_TI_SCI_CLK=y
+# CONFIG_TI_SCI_CLK_PROBE_FROM_FW is not set
+CONFIG_TI_SYSCON_CLK=y
+
+#
+# Clock support for Amlogic platforms
+#
+CONFIG_COMMON_CLK_MESON_REGMAP=y
+CONFIG_COMMON_CLK_MESON_DUALDIV=y
+CONFIG_COMMON_CLK_MESON_MPLL=y
+CONFIG_COMMON_CLK_MESON_PHASE=m
+CONFIG_COMMON_CLK_MESON_PLL=y
+CONFIG_COMMON_CLK_MESON_SCLK_DIV=m
+CONFIG_COMMON_CLK_MESON_VID_PLL_DIV=y
+CONFIG_COMMON_CLK_MESON_CLKC_UTILS=y
+CONFIG_COMMON_CLK_MESON_AO_CLKC=y
+CONFIG_COMMON_CLK_MESON_EE_CLKC=y
+CONFIG_COMMON_CLK_MESON_CPU_DYNDIV=y
+CONFIG_COMMON_CLK_GXBB=y
+CONFIG_COMMON_CLK_AXG=y
+CONFIG_COMMON_CLK_AXG_AUDIO=m
+# CONFIG_COMMON_CLK_A1_PLL is not set
+# CONFIG_COMMON_CLK_A1_PERIPHERALS is not set
+CONFIG_COMMON_CLK_G12A=y
+# end of Clock support for Amlogic platforms
+
+CONFIG_ARMADA_AP_CP_HELPER=y
+CONFIG_ARMADA_37XX_CLK=y
+CONFIG_ARMADA_AP806_SYSCON=y
+CONFIG_ARMADA_CP110_SYSCON=y
+CONFIG_QCOM_GDSC=y
+CONFIG_COMMON_CLK_QCOM=y
+# CONFIG_QCOM_A53PLL is not set
+# CONFIG_QCOM_A7PLL is not set
+# CONFIG_QCOM_CLK_APCS_MSM8916 is not set
+# CONFIG_QCOM_CLK_APCC_MSM8996 is not set
+# CONFIG_IPQ_APSS_PLL is not set
+# CONFIG_IPQ_GCC_4019 is not set
+# CONFIG_IPQ_GCC_5018 is not set
+# CONFIG_IPQ_GCC_5332 is not set
+# CONFIG_IPQ_GCC_6018 is not set
+# CONFIG_IPQ_GCC_8074 is not set
+# CONFIG_IPQ_GCC_9574 is not set
+CONFIG_MSM_GCC_8916=y
+# CONFIG_MSM_GCC_8917 is not set
+# CONFIG_MSM_GCC_8939 is not set
+# CONFIG_MSM_GCC_8953 is not set
+# CONFIG_MSM_GCC_8976 is not set
+# CONFIG_MSM_MMCC_8994 is not set
+# CONFIG_MSM_GCC_8994 is not set
+CONFIG_MSM_GCC_8996=y
+CONFIG_MSM_MMCC_8996=y
+# CONFIG_MSM_GCC_8998 is not set
+# CONFIG_MSM_GPUCC_8998 is not set
+# CONFIG_MSM_MMCC_8998 is not set
+# CONFIG_QCM_GCC_2290 is not set
+# CONFIG_QCM_DISPCC_2290 is not set
+# CONFIG_QCS_GCC_404 is not set
+# CONFIG_SC_CAMCC_7180 is not set
+# CONFIG_SC_CAMCC_7280 is not set
+# CONFIG_SC_DISPCC_7180 is not set
+# CONFIG_SC_DISPCC_7280 is not set
+# CONFIG_SC_DISPCC_8280XP is not set
+# CONFIG_SA_GCC_8775P is not set
+# CONFIG_SA_GPUCC_8775P is not set
+# CONFIG_SC_GCC_7180 is not set
+# CONFIG_SC_GCC_7280 is not set
+# CONFIG_SC_GCC_8180X is not set
+# CONFIG_SC_GCC_8280XP is not set
+# CONFIG_SC_GPUCC_7180 is not set
+# CONFIG_SC_GPUCC_7280 is not set
+# CONFIG_SC_GPUCC_8280XP is not set
+# CONFIG_SC_LPASSCC_7280 is not set
+# CONFIG_SC_LPASSCC_8280XP is not set
+# CONFIG_SC_LPASS_CORECC_7180 is not set
+# CONFIG_SC_LPASS_CORECC_7280 is not set
+# CONFIG_SC_MSS_7180 is not set
+# CONFIG_SC_VIDEOCC_7180 is not set
+# CONFIG_SC_VIDEOCC_7280 is not set
+CONFIG_SDM_CAMCC_845=m
+# CONFIG_SDM_GCC_660 is not set
+# CONFIG_SDM_MMCC_660 is not set
+# CONFIG_SDM_GPUCC_660 is not set
+# CONFIG_QCS_TURING_404 is not set
+# CONFIG_QCS_Q6SSTOP_404 is not set
+# CONFIG_QDU_GCC_1000 is not set
+CONFIG_SDM_GCC_845=y
+CONFIG_SDM_GPUCC_845=m
+CONFIG_SDM_VIDEOCC_845=m
+CONFIG_SDM_DISPCC_845=m
+# CONFIG_SDM_LPASSCC_845 is not set
+# CONFIG_SDX_GCC_75 is not set
+# CONFIG_SM_CAMCC_6350 is not set
+# CONFIG_SM_CAMCC_8250 is not set
+# CONFIG_SM_CAMCC_8450 is not set
+# CONFIG_SM_GCC_6115 is not set
+# CONFIG_SM_GCC_6125 is not set
+# CONFIG_SM_GCC_6350 is not set
+# CONFIG_SM_GCC_6375 is not set
+# CONFIG_SM_GCC_7150 is not set
+# CONFIG_SM_GCC_8150 is not set
+# CONFIG_SM_GCC_8250 is not set
+# CONFIG_SM_GCC_8350 is not set
+# CONFIG_SM_GCC_8450 is not set
+# CONFIG_SM_GCC_8550 is not set
+# CONFIG_SM_GPUCC_6115 is not set
+# CONFIG_SM_GPUCC_6125 is not set
+# CONFIG_SM_GPUCC_6375 is not set
+# CONFIG_SM_GPUCC_6350 is not set
+# CONFIG_SM_GPUCC_8150 is not set
+# CONFIG_SM_GPUCC_8250 is not set
+# CONFIG_SM_GPUCC_8350 is not set
+# CONFIG_SM_GPUCC_8450 is not set
+# CONFIG_SM_GPUCC_8550 is not set
+# CONFIG_SM_TCSRCC_8550 is not set
+# CONFIG_SM_VIDEOCC_8150 is not set
+# CONFIG_SM_VIDEOCC_8250 is not set
+# CONFIG_SM_VIDEOCC_8350 is not set
+# CONFIG_SM_VIDEOCC_8550 is not set
+CONFIG_QCOM_HFPLL=y
+# CONFIG_KPSS_XCC is not set
+# CONFIG_CLK_GFM_LPASS_SM8250 is not set
+# CONFIG_SM_VIDEOCC_8450 is not set
+CONFIG_CLK_RENESAS=y
+# CONFIG_CLK_RCAR_USB2_CLOCK_SEL is not set
+CONFIG_COMMON_CLK_ROCKCHIP=y
+CONFIG_CLK_PX30=y
+CONFIG_CLK_RK3308=y
+CONFIG_CLK_RK3328=y
+CONFIG_CLK_RK3368=y
+CONFIG_CLK_RK3399=y
+CONFIG_CLK_RK3568=y
+CONFIG_CLK_RK3588=y
+CONFIG_SUNXI_CCU=y
+CONFIG_SUN50I_A64_CCU=y
+CONFIG_SUN50I_A100_CCU=y
+CONFIG_SUN50I_A100_R_CCU=y
+CONFIG_SUN50I_H6_CCU=y
+CONFIG_SUN50I_H616_CCU=y
+CONFIG_SUN50I_H6_R_CCU=y
+CONFIG_SUN6I_RTC_CCU=y
+CONFIG_SUN8I_H3_CCU=y
+CONFIG_SUN8I_DE2_CCU=y
+CONFIG_SUN8I_R_CCU=y
+# CONFIG_XILINX_VCU is not set
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+# CONFIG_HWSPINLOCK is not set
+
+#
+# Clock Source drivers
+#
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_ACPI=y
+CONFIG_TIMER_PROBE=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_ROCKCHIP_TIMER=y
+CONFIG_SUN4I_TIMER=y
+# CONFIG_TEGRA186_TIMER is not set
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
+CONFIG_FSL_ERRATUM_A008585=y
+CONFIG_HISILICON_ERRATUM_161010101=y
+CONFIG_ARM64_ERRATUM_858921=y
+CONFIG_SUN50I_ERRATUM_UNKNOWN1=y
+CONFIG_ARM_TIMER_SP804=y
+# CONFIG_RENESAS_OSTM is not set
+CONFIG_TIMER_IMX_SYS_CTR=y
+# end of Clock Source drivers
+
+CONFIG_MAILBOX=y
+CONFIG_ARM_MHU=m
+# CONFIG_ARM_MHU_V2 is not set
+CONFIG_IMX_MBOX=m
+CONFIG_PLATFORM_MHU=m
+# CONFIG_PL320_MBOX is not set
+CONFIG_ARMADA_37XX_RWTM_MBOX=m
+CONFIG_OMAP2PLUS_MBOX=y
+CONFIG_OMAP_MBOX_KFIFO_SIZE=256
+# CONFIG_ROCKCHIP_MBOX is not set
+CONFIG_PCC=y
+# CONFIG_ALTERA_MBOX is not set
+CONFIG_BCM2835_MBOX=y
+CONFIG_TI_MESSAGE_MANAGER=y
+CONFIG_HI3660_MBOX=y
+CONFIG_HI6220_MBOX=y
+# CONFIG_MAILBOX_TEST is not set
+CONFIG_QCOM_APCS_IPC=m
+# CONFIG_TEGRA_HSP_MBOX is not set
+CONFIG_XGENE_SLIMPRO_MBOX=m
+CONFIG_SUN6I_MSGBOX=y
+# CONFIG_QCOM_IPCC is not set
+CONFIG_IOMMU_IOVA=y
+CONFIG_IOMMU_API=y
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Generic IOMMU Pagetable Support
+#
+CONFIG_IOMMU_IO_PGTABLE=y
+CONFIG_IOMMU_IO_PGTABLE_LPAE=y
+# CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST is not set
+# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
+# CONFIG_IOMMU_IO_PGTABLE_DART is not set
+# end of Generic IOMMU Pagetable Support
+
+# CONFIG_IOMMU_DEBUGFS is not set
+# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
+# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
+CONFIG_OF_IOMMU=y
+CONFIG_IOMMU_DMA=y
+# CONFIG_IOMMUFD is not set
+CONFIG_ROCKCHIP_IOMMU=y
+# CONFIG_SUN50I_IOMMU is not set
+# CONFIG_IPMMU_VMSA is not set
+CONFIG_ARM_SMMU=y
+# CONFIG_ARM_SMMU_LEGACY_DT_BINDINGS is not set
+CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT=y
+CONFIG_ARM_SMMU_QCOM=y
+# CONFIG_ARM_SMMU_QCOM_DEBUG is not set
+CONFIG_ARM_SMMU_V3=y
+# CONFIG_ARM_SMMU_V3_SVA is not set
+CONFIG_QCOM_IOMMU=y
+# CONFIG_VIRTIO_IOMMU is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_REMOTEPROC is not set
+# end of Remoteproc drivers
+
+#
+# Rpmsg drivers
+#
+CONFIG_RPMSG=m
+# CONFIG_RPMSG_CHAR is not set
+# CONFIG_RPMSG_CTRL is not set
+# CONFIG_RPMSG_NS is not set
+CONFIG_RPMSG_QCOM_GLINK=m
+CONFIG_RPMSG_QCOM_GLINK_RPM=m
+# CONFIG_RPMSG_VIRTIO is not set
+# end of Rpmsg drivers
+
+# CONFIG_SOUNDWIRE is not set
+
+#
+# SOC (System On Chip) specific Drivers
+#
+
+#
+# Amlogic SoC drivers
+#
+# CONFIG_MESON_CANVAS is not set
+CONFIG_MESON_CLK_MEASURE=y
+CONFIG_MESON_GX_SOCINFO=y
+CONFIG_MESON_GX_PM_DOMAINS=y
+CONFIG_MESON_EE_PM_DOMAINS=y
+CONFIG_MESON_SECURE_PM_DOMAINS=y
+# end of Amlogic SoC drivers
+
+#
+# Broadcom SoC drivers
+#
+CONFIG_BCM2835_POWER=y
+# CONFIG_RASPBERRYPI_POWER is not set
+# CONFIG_SOC_BRCMSTB is not set
+# end of Broadcom SoC drivers
+
+#
+# NXP/Freescale QorIQ SoC drivers
+#
+# CONFIG_FSL_DPAA is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_MC_DPIO is not set
+CONFIG_DPAA2_CONSOLE=y
+# CONFIG_FSL_RCPM is not set
+# end of NXP/Freescale QorIQ SoC drivers
+
+#
+# fujitsu SoC drivers
+#
+# CONFIG_A64FX_DIAG is not set
+# end of fujitsu SoC drivers
+
+#
+# Hisilicon SoC drivers
+#
+# CONFIG_KUNPENG_HCCS is not set
+# end of Hisilicon SoC drivers
+
+#
+# i.MX SoC drivers
+#
+CONFIG_IMX_GPCV2_PM_DOMAINS=y
+CONFIG_SOC_IMX8M=y
+CONFIG_SOC_IMX9=y
+CONFIG_IMX8M_BLK_CTRL=y
+CONFIG_IMX9_BLK_CTRL=y
+# end of i.MX SoC drivers
+
+#
+# Enable LiteX SoC Builder specific drivers
+#
+# CONFIG_LITEX_SOC_CONTROLLER is not set
+# end of Enable LiteX SoC Builder specific drivers
+
+# CONFIG_WPCM450_SOC is not set
+
+#
+# Qualcomm SoC drivers
+#
+# CONFIG_QCOM_AOSS_QMP is not set
+# CONFIG_QCOM_COMMAND_DB is not set
+# CONFIG_QCOM_CPR is not set
+# CONFIG_QCOM_GENI_SE is not set
+# CONFIG_QCOM_GSBI is not set
+# CONFIG_QCOM_LLCC is not set
+# CONFIG_QCOM_OCMEM is not set
+# CONFIG_QCOM_RAMP_CTRL is not set
+# CONFIG_QCOM_RMTFS_MEM is not set
+# CONFIG_QCOM_RPM_MASTER_STATS is not set
+# CONFIG_QCOM_RPMH is not set
+# CONFIG_QCOM_SMD_RPM is not set
+# CONFIG_QCOM_SPM is not set
+# CONFIG_QCOM_WCNSS_CTRL is not set
+# CONFIG_QCOM_APR is not set
+# CONFIG_QCOM_ICC_BWMON is not set
+# end of Qualcomm SoC drivers
+
+CONFIG_SOC_RENESAS=y
+# CONFIG_ARCH_R8A77995 is not set
+# CONFIG_ARCH_R8A77990 is not set
+# CONFIG_ARCH_R8A77951 is not set
+# CONFIG_ARCH_R8A77965 is not set
+# CONFIG_ARCH_R8A77960 is not set
+# CONFIG_ARCH_R8A77961 is not set
+# CONFIG_ARCH_R8A779F0 is not set
+# CONFIG_ARCH_R8A77980 is not set
+# CONFIG_ARCH_R8A77970 is not set
+# CONFIG_ARCH_R8A779A0 is not set
+# CONFIG_ARCH_R8A779G0 is not set
+# CONFIG_ARCH_R8A774C0 is not set
+# CONFIG_ARCH_R8A774E1 is not set
+# CONFIG_ARCH_R8A774A1 is not set
+# CONFIG_ARCH_R8A774B1 is not set
+# CONFIG_ARCH_R9A07G043 is not set
+# CONFIG_ARCH_R9A07G044 is not set
+# CONFIG_ARCH_R9A07G054 is not set
+# CONFIG_ARCH_R9A09G011 is not set
+CONFIG_ROCKCHIP_GRF=y
+# CONFIG_ROCKCHIP_IODOMAIN is not set
+# CONFIG_ROCKCHIP_PM_DOMAINS is not set
+CONFIG_SUNXI_MBUS=y
+CONFIG_SUNXI_SRAM=y
+# CONFIG_SUN20I_PPU is not set
+# CONFIG_ARCH_TEGRA_132_SOC is not set
+# CONFIG_ARCH_TEGRA_210_SOC is not set
+# CONFIG_ARCH_TEGRA_186_SOC is not set
+# CONFIG_ARCH_TEGRA_194_SOC is not set
+# CONFIG_ARCH_TEGRA_234_SOC is not set
+CONFIG_SOC_TEGRA_FUSE=y
+CONFIG_SOC_TI=y
+# CONFIG_TI_SCI_PM_DOMAINS is not set
+CONFIG_TI_K3_RINGACC=y
+CONFIG_TI_K3_SOCINFO=y
+# CONFIG_TI_PRUSS is not set
+CONFIG_TI_SCI_INTA_MSI_DOMAIN=y
+
+#
+# Xilinx SoC drivers
+#
+# end of Xilinx SoC drivers
+# end of SOC (System On Chip) specific Drivers
+
+CONFIG_PM_DEVFREQ=y
+
+#
+# DEVFREQ Governors
+#
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m
+# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
+# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
+# CONFIG_DEVFREQ_GOV_USERSPACE is not set
+# CONFIG_DEVFREQ_GOV_PASSIVE is not set
+
+#
+# DEVFREQ Drivers
+#
+# CONFIG_ARM_IMX_BUS_DEVFREQ is not set
+# CONFIG_ARM_IMX8M_DDRC_DEVFREQ is not set
+# CONFIG_ARM_RK3399_DMC_DEVFREQ is not set
+# CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ is not set
+# CONFIG_PM_DEVFREQ_EVENT is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_NTB is not set
+# CONFIG_PWM is not set
+
+#
+# IRQ chip support
+#
+CONFIG_IRQCHIP=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_PM=y
+CONFIG_ARM_GIC_MAX_NR=1
+CONFIG_ARM_GIC_V2M=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_ARM_GIC_V3_ITS=y
+CONFIG_ARM_GIC_V3_ITS_PCI=y
+CONFIG_ARM_GIC_V3_ITS_FSL_MC=y
+# CONFIG_AL_FIC is not set
+CONFIG_BRCMSTB_L2_IRQ=y
+CONFIG_HISILICON_IRQ_MBIGEN=y
+CONFIG_SUN6I_R_INTC=y
+CONFIG_SUNXI_NMI_INTC=y
+# CONFIG_XILINX_INTC is not set
+CONFIG_IMX_GPCV2=y
+CONFIG_MVEBU_GICP=y
+CONFIG_MVEBU_ICU=y
+CONFIG_MVEBU_ODMI=y
+CONFIG_MVEBU_PIC=y
+CONFIG_MVEBU_SEI=y
+CONFIG_LS_EXTIRQ=y
+CONFIG_LS_SCFG_MSI=y
+CONFIG_PARTITION_PERCPU=y
+# CONFIG_QCOM_IRQ_COMBINER is not set
+CONFIG_MESON_IRQ_GPIO=y
+# CONFIG_QCOM_PDC is not set
+# CONFIG_QCOM_MPM is not set
+CONFIG_IMX_IRQSTEER=y
+CONFIG_IMX_INTMUX=y
+CONFIG_IMX_MU_MSI=m
+CONFIG_TI_SCI_INTR_IRQCHIP=y
+CONFIG_TI_SCI_INTA_IRQCHIP=y
+# end of IRQ chip support
+
+# CONFIG_IPACK_BUS is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_RESET_CONTROLLER=y
+# CONFIG_RESET_IMX7 is not set
+CONFIG_RESET_MESON=y
+# CONFIG_RESET_MESON_AUDIO_ARB is not set
+# CONFIG_RESET_QCOM_AOSS is not set
+# CONFIG_RESET_QCOM_PDC is not set
+CONFIG_RESET_RASPBERRYPI=m
+CONFIG_RESET_SCMI=y
+CONFIG_RESET_SIMPLE=y
+CONFIG_RESET_SUNXI=y
+# CONFIG_RESET_TI_SCI is not set
+# CONFIG_RESET_TI_SYSCON is not set
+# CONFIG_RESET_TI_TPS380X is not set
+CONFIG_COMMON_RESET_HI3660=y
+CONFIG_COMMON_RESET_HI6220=y
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PHY_MIPI_DPHY=y
+# CONFIG_PHY_XGENE is not set
+# CONFIG_PHY_CAN_TRANSCEIVER is not set
+# CONFIG_PHY_SUN6I_MIPI_DPHY is not set
+# CONFIG_PHY_SUN9I_USB is not set
+# CONFIG_PHY_SUN50I_USB3 is not set
+CONFIG_PHY_MESON8B_USB2=y
+CONFIG_PHY_MESON_GXL_USB2=y
+CONFIG_PHY_MESON_G12A_MIPI_DPHY_ANALOG=y
+CONFIG_PHY_MESON_G12A_USB2=y
+CONFIG_PHY_MESON_G12A_USB3_PCIE=y
+CONFIG_PHY_MESON_AXG_PCIE=y
+CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG=y
+CONFIG_PHY_MESON_AXG_MIPI_DPHY=y
+
+#
+# PHY drivers for Broadcom platforms
+#
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# end of PHY drivers for Broadcom platforms
+
+# CONFIG_PHY_CADENCE_TORRENT is not set
+# CONFIG_PHY_CADENCE_DPHY is not set
+# CONFIG_PHY_CADENCE_DPHY_RX is not set
+# CONFIG_PHY_CADENCE_SIERRA is not set
+# CONFIG_PHY_CADENCE_SALVO is not set
+CONFIG_PHY_FSL_IMX8MQ_USB=y
+# CONFIG_PHY_MIXEL_LVDS_PHY is not set
+# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
+# CONFIG_PHY_FSL_IMX8M_PCIE is not set
+# CONFIG_PHY_FSL_LYNX_28G is not set
+# CONFIG_PHY_HI6220_USB is not set
+# CONFIG_PHY_HI3660_USB is not set
+# CONFIG_PHY_HI3670_USB is not set
+# CONFIG_PHY_HI3670_PCIE is not set
+# CONFIG_PHY_HISTB_COMBPHY is not set
+# CONFIG_PHY_HISI_INNO_USB2 is not set
+CONFIG_PHY_MVEBU_A3700_COMPHY=y
+CONFIG_PHY_MVEBU_A3700_UTMI=y
+# CONFIG_PHY_MVEBU_A38X_COMPHY is not set
+# CONFIG_PHY_MVEBU_CP110_COMPHY is not set
+# CONFIG_PHY_MVEBU_CP110_UTMI is not set
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_PHY_LAN966X_SERDES is not set
+# CONFIG_PHY_MAPPHONE_MDM6600 is not set
+# CONFIG_PHY_OCELOT_SERDES is not set
+# CONFIG_PHY_QCOM_APQ8064_SATA is not set
+# CONFIG_PHY_QCOM_EDP is not set
+# CONFIG_PHY_QCOM_IPQ4019_USB is not set
+# CONFIG_PHY_QCOM_IPQ806X_SATA is not set
+# CONFIG_PHY_QCOM_PCIE2 is not set
+# CONFIG_PHY_QCOM_QMP is not set
+# CONFIG_PHY_QCOM_QUSB2 is not set
+# CONFIG_PHY_QCOM_SNPS_EUSB2 is not set
+# CONFIG_PHY_QCOM_EUSB2_REPEATER is not set
+# CONFIG_PHY_QCOM_M31_USB is not set
+# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set
+# CONFIG_PHY_QCOM_USB_HS_28NM is not set
+# CONFIG_PHY_QCOM_USB_SS is not set
+# CONFIG_PHY_QCOM_IPQ806X_USB is not set
+# CONFIG_PHY_QCOM_SGMII_ETH is not set
+# CONFIG_PHY_R8A779F0_ETHERNET_SERDES is not set
+# CONFIG_PHY_RCAR_GEN2 is not set
+# CONFIG_PHY_RCAR_GEN3_PCIE is not set
+# CONFIG_PHY_RCAR_GEN3_USB2 is not set
+# CONFIG_PHY_RCAR_GEN3_USB3 is not set
+# CONFIG_PHY_ROCKCHIP_DP is not set
+# CONFIG_PHY_ROCKCHIP_DPHY_RX0 is not set
+# CONFIG_PHY_ROCKCHIP_EMMC is not set
+# CONFIG_PHY_ROCKCHIP_INNO_HDMI is not set
+# CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY is not set
+# CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY is not set
+# CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY is not set
+# CONFIG_PHY_ROCKCHIP_PCIE is not set
+# CONFIG_PHY_ROCKCHIP_SNPS_PCIE3 is not set
+# CONFIG_PHY_ROCKCHIP_TYPEC is not set
+# CONFIG_PHY_ROCKCHIP_USB is not set
+# CONFIG_PHY_TEGRA_XUSB is not set
+# CONFIG_PHY_AM654_SERDES is not set
+# CONFIG_PHY_J721E_WIZ is not set
+# CONFIG_OMAP_USB2 is not set
+# end of PHY Subsystem
+
+CONFIG_POWERCAP=y
+# CONFIG_IDLE_INJECT is not set
+# CONFIG_ARM_SCMI_POWERCAP is not set
+# CONFIG_DTPM is not set
+# CONFIG_MCB is not set
+
+#
+# Performance monitor support
+#
+# CONFIG_ARM_CCI_PMU is not set
+# CONFIG_ARM_CCN is not set
+# CONFIG_ARM_CMN is not set
+CONFIG_ARM_PMU=y
+CONFIG_ARM_PMU_ACPI=y
+# CONFIG_ARM_SMMU_V3_PMU is not set
+CONFIG_ARM_PMUV3=y
+# CONFIG_ARM_DSU_PMU is not set
+# CONFIG_FSL_IMX8_DDR_PMU is not set
+# CONFIG_FSL_IMX9_DDR_PMU is not set
+# CONFIG_QCOM_L2_PMU is not set
+# CONFIG_QCOM_L3_PMU is not set
+CONFIG_THUNDERX2_PMU=m
+# CONFIG_XGENE_PMU is not set
+# CONFIG_ARM_SPE_PMU is not set
+# CONFIG_ARM_DMC620_PMU is not set
+# CONFIG_MARVELL_CN10K_TAD_PMU is not set
+# CONFIG_ALIBABA_UNCORE_DRW_PMU is not set
+# CONFIG_HISI_PMU is not set
+# CONFIG_HISI_PCIE_PMU is not set
+# CONFIG_HNS3_PMU is not set
+# CONFIG_MARVELL_CN10K_DDR_PMU is not set
+# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set
+# CONFIG_MESON_DDR_PMU is not set
+# end of Performance monitor support
+
+CONFIG_RAS=y
+CONFIG_USB4=m
+CONFIG_USB4_NET=m
+
+#
+# Android
+#
+# CONFIG_ANDROID_BINDER_IPC is not set
+# end of Android
+
+CONFIG_LIBNVDIMM=m
+CONFIG_BLK_DEV_PMEM=m
+CONFIG_ND_CLAIM=y
+CONFIG_ND_BTT=m
+CONFIG_BTT=y
+CONFIG_OF_PMEM=m
+CONFIG_DAX=y
+# CONFIG_DEV_DAX is not set
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+
+#
+# Layout Types
+#
+# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
+# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
+# end of Layout Types
+
+# CONFIG_NVMEM_IMX_IIM is not set
+# CONFIG_NVMEM_IMX_OCOTP is not set
+# CONFIG_NVMEM_IMX_OCOTP_ELE is not set
+# CONFIG_NVMEM_LAYERSCAPE_SFP is not set
+# CONFIG_NVMEM_MESON_EFUSE is not set
+# CONFIG_NVMEM_MESON_MX_EFUSE is not set
+# CONFIG_NVMEM_QCOM_QFPROM is not set
+# CONFIG_NVMEM_QCOM_SEC_QFPROM is not set
+# CONFIG_NVMEM_RMEM is not set
+# CONFIG_NVMEM_ROCKCHIP_EFUSE is not set
+# CONFIG_NVMEM_ROCKCHIP_OTP is not set
+# CONFIG_NVMEM_SNVS_LPGPR is not set
+# CONFIG_NVMEM_SUNXI_SID is not set
+
+#
+# HW tracing support
+#
+# CONFIG_STM is not set
+# CONFIG_INTEL_TH is not set
+# CONFIG_HISI_PTT is not set
+# end of HW tracing support
+
+# CONFIG_FPGA is not set
+# CONFIG_FSI is not set
+# CONFIG_TEE is not set
+CONFIG_PM_OPP=y
+# CONFIG_SIOX is not set
+# CONFIG_SLIMBUS is not set
+# CONFIG_INTERCONNECT is not set
+# CONFIG_COUNTER is not set
+# CONFIG_MOST is not set
+# CONFIG_PECI is not set
+# CONFIG_HTE is not set
+# CONFIG_CDX_BUS is not set
+# end of Device Drivers
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_VALIDATE_FS_PARSER is not set
+CONFIG_FS_IOMAP=y
+CONFIG_BUFFER_HEAD=y
+CONFIG_LEGACY_DIRECT_IO=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=m
+CONFIG_EXT4_USE_FOR_EXT2=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=m
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_F2FS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FS_ENCRYPTION is not set
+# CONFIG_FS_VERITY is not set
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_VIRTIO_FS=m
+CONFIG_OVERLAY_FS=m
+# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
+CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
+# CONFIG_OVERLAY_FS_INDEX is not set
+# CONFIG_OVERLAY_FS_XINO_AUTO is not set
+# CONFIG_OVERLAY_FS_METACOPY is not set
+# CONFIG_OVERLAY_FS_DEBUG is not set
+
+#
+# Caches
+#
+CONFIG_NETFS_SUPPORT=m
+CONFIG_NETFS_STATS=y
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_CACHEFILES is not set
+# end of Caches
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+# end of CD-ROM/DVD Filesystems
+
+#
+# DOS/FAT/EXFAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_EXFAT_FS=m
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS3_FS is not set
+# end of DOS/FAT/EXFAT/NT Filesystems
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_CHILDREN=y
+CONFIG_KERNFS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TMPFS_INODE64 is not set
+# CONFIG_TMPFS_QUOTA is not set
+CONFIG_ARCH_SUPPORTS_HUGETLBFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_EFIVAR_FS=m
+# end of Pseudo filesystems
+
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ORANGEFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_FILE_CACHE=y
+# CONFIG_SQUASHFS_FILE_DIRECT is not set
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
+CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
+# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZSTD=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_PSTORE=y
+CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
+CONFIG_PSTORE_COMPRESS=y
+# CONFIG_PSTORE_CONSOLE is not set
+# CONFIG_PSTORE_PMSG is not set
+# CONFIG_PSTORE_RAM is not set
+# CONFIG_PSTORE_BLK is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_EROFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+# CONFIG_UNICODE is not set
+CONFIG_IO_WQ=y
+# end of File systems
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_REQUEST_CACHE is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_TRUSTED_KEYS is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_KEY_DH_OPERATIONS is not set
+CONFIG_SECURITY_DMESG_RESTRICT=y
+# CONFIG_SECURITY is not set
+CONFIG_SECURITYFS=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
+# CONFIG_STATIC_USERMODEHELPER is not set
+# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
+
+#
+# Kernel hardening options
+#
+
+#
+# Memory initialization
+#
+CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
+CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
+CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
+CONFIG_INIT_STACK_NONE=y
+# CONFIG_INIT_STACK_ALL_PATTERN is not set
+# CONFIG_INIT_STACK_ALL_ZERO is not set
+# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
+# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
+CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
+# CONFIG_ZERO_CALL_USED_REGS is not set
+# end of Memory initialization
+
+#
+# Hardening of kernel data structures
+#
+CONFIG_LIST_HARDENED=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
+# end of Hardening of kernel data structures
+
+CONFIG_RANDSTRUCT_NONE=y
+# end of Kernel hardening options
+# end of Security options
+
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_ASYNC_PQ=y
+CONFIG_ASYNC_RAID6_RECOV=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_SIG2=y
+CONFIG_CRYPTO_SKCIPHER=y
+CONFIG_CRYPTO_SKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=m
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_AKCIPHER=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_KPP=m
+CONFIG_CRYPTO_ACOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_ENGINE=m
+# end of Crypto core or helper
+
+#
+# Public-key cryptography
+#
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_DH=m
+# CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set
+CONFIG_CRYPTO_ECC=m
+CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
+CONFIG_CRYPTO_ECRDSA=m
+# CONFIG_CRYPTO_SM2 is not set
+# CONFIG_CRYPTO_CURVE25519 is not set
+# end of Public-key cryptography
+
+#
+# Block ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_ANUBIS=m
+# CONFIG_CRYPTO_ARIA is not set
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+# CONFIG_CRYPTO_SM4_GENERIC is not set
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+# end of Block ciphers
+
+#
+# Length-preserving ciphers and modes
+#
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CHACHA20=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_HCTR2 is not set
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_NHPOLY1305=m
+# end of Length-preserving ciphers and modes
+
+#
+# AEAD (authenticated encryption with associated data) ciphers
+#
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_AEGIS128_SIMD=y
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_GENIV=m
+CONFIG_CRYPTO_SEQIV=m
+CONFIG_CRYPTO_ECHAINIV=m
+CONFIG_CRYPTO_ESSIV=y
+# end of AEAD (authenticated encryption with associated data) ciphers
+
+#
+# Hashes, digests, and MACs
+#
+# CONFIG_CRYPTO_BLAKE2B is not set
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_GHASH=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_POLYVAL=m
+CONFIG_CRYPTO_POLY1305=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_SHA3=m
+# CONFIG_CRYPTO_SM3_GENERIC is not set
+CONFIG_CRYPTO_STREEBOG=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_XXHASH=m
+# end of Hashes, digests, and MACs
+
+#
+# CRCs (cyclic redundancy checks)
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_CRC32=m
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_CRC64_ROCKSOFT=y
+# end of CRCs (cyclic redundancy checks)
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_ZSTD=m
+# end of Compression
+
+#
+# Random number generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_DRBG_MENU=m
+CONFIG_CRYPTO_DRBG_HMAC=y
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+CONFIG_CRYPTO_DRBG=m
+CONFIG_CRYPTO_JITTERENTROPY=m
+# CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE is not set
+# end of Random number generation
+
+#
+# Userspace interface
+#
+CONFIG_CRYPTO_USER_API=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
+CONFIG_CRYPTO_STATS=y
+# end of Userspace interface
+
+CONFIG_CRYPTO_HASH_INFO=y
+# CONFIG_CRYPTO_NHPOLY1305_NEON is not set
+CONFIG_CRYPTO_CHACHA20_NEON=m
+
+#
+# Accelerated Cryptographic Algorithms for CPU (arm64)
+#
+CONFIG_CRYPTO_GHASH_ARM64_CE=m
+CONFIG_CRYPTO_POLY1305_NEON=m
+CONFIG_CRYPTO_SHA1_ARM64_CE=m
+CONFIG_CRYPTO_SHA256_ARM64=m
+CONFIG_CRYPTO_SHA2_ARM64_CE=m
+CONFIG_CRYPTO_SHA512_ARM64=m
+CONFIG_CRYPTO_SHA512_ARM64_CE=m
+CONFIG_CRYPTO_SHA3_ARM64=m
+# CONFIG_CRYPTO_SM3_NEON is not set
+# CONFIG_CRYPTO_SM3_ARM64_CE is not set
+CONFIG_CRYPTO_POLYVAL_ARM64_CE=m
+# CONFIG_CRYPTO_AES_ARM64 is not set
+CONFIG_CRYPTO_AES_ARM64_CE=m
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=m
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=m
+CONFIG_CRYPTO_AES_ARM64_BS=m
+# CONFIG_CRYPTO_SM4_ARM64_CE is not set
+# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
+# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=m
+# CONFIG_CRYPTO_SM4_ARM64_CE_CCM is not set
+# CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set
+CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m
+# end of Accelerated Cryptographic Algorithms for CPU (arm64)
+
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_ALLWINNER=y
+# CONFIG_CRYPTO_DEV_SUN4I_SS is not set
+CONFIG_CRYPTO_DEV_SUN8I_CE=m
+# CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG is not set
+# CONFIG_CRYPTO_DEV_SUN8I_CE_HASH is not set
+# CONFIG_CRYPTO_DEV_SUN8I_CE_PRNG is not set
+# CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG is not set
+# CONFIG_CRYPTO_DEV_SUN8I_SS is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=m
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=m
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC=m
+CONFIG_CRYPTO_DEV_FSL_CAAM=m
+# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM_JR=m
+CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9
+# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y
+CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API=y
+# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set
+# CONFIG_CRYPTO_DEV_SAHARA is not set
+# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_MXS_DCP is not set
+CONFIG_CRYPTO_DEV_CPT=m
+CONFIG_CAVIUM_CPT=m
+CONFIG_CRYPTO_DEV_NITROX=m
+CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m
+CONFIG_CRYPTO_DEV_MARVELL=m
+CONFIG_CRYPTO_DEV_MARVELL_CESA=m
+# CONFIG_CRYPTO_DEV_OCTEONTX_CPT is not set
+# CONFIG_CRYPTO_DEV_OCTEONTX2_CPT is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_C62X is not set
+# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
+# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y
+CONFIG_CRYPTO_DEV_QCE_SHA=y
+CONFIG_CRYPTO_DEV_QCE_AEAD=y
+CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL=y
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER is not set
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set
+# CONFIG_CRYPTO_DEV_QCE_ENABLE_AEAD is not set
+CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512
+CONFIG_CRYPTO_DEV_QCOM_RNG=m
+CONFIG_CRYPTO_DEV_ROCKCHIP=m
+# CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG is not set
+CONFIG_CRYPTO_DEV_CHELSIO=m
+CONFIG_CRYPTO_DEV_VIRTIO=m
+# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
+# CONFIG_CRYPTO_DEV_CCREE is not set
+# CONFIG_CRYPTO_DEV_HISI_SEC is not set
+# CONFIG_CRYPTO_DEV_HISI_SEC2 is not set
+# CONFIG_CRYPTO_DEV_HISI_ZIP is not set
+# CONFIG_CRYPTO_DEV_HISI_HPRE is not set
+# CONFIG_CRYPTO_DEV_HISI_TRNG is not set
+# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
+# CONFIG_CRYPTO_DEV_SA2UL is not set
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
+CONFIG_PKCS7_MESSAGE_PARSER=y
+# CONFIG_PKCS7_TEST_KEY is not set
+CONFIG_SIGNED_PE_FILE_VERIFICATION=y
+# CONFIG_FIPS_SIGNATURE_SELFTEST is not set
+
+#
+# Certificates for signature checking
+#
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
+# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
+# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
+# end of Certificates for signature checking
+
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=y
+CONFIG_RAID6_PQ_BENCHMARK=y
+CONFIG_LINEAR_RANGES=y
+# CONFIG_PACKING is not set
+CONFIG_BITREVERSE=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_CORDIC=m
+# CONFIG_PRIME_NUMBERS is not set
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
+CONFIG_INDIRECT_PIO=y
+# CONFIG_TRACE_MMIO_ACCESS is not set
+
+#
+# Crypto library routines
+#
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_ARC4=m
+CONFIG_CRYPTO_LIB_GF128MUL=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m
+CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
+CONFIG_CRYPTO_LIB_CHACHA=m
+CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_DES=m
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9
+CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m
+CONFIG_CRYPTO_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_SHA256=y
+# end of Crypto library routines
+
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC64_ROCKSOFT=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC64=y
+# CONFIG_CRC4 is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+CONFIG_CRC8=m
+CONFIG_XXHASH=y
+CONFIG_AUDIT_GENERIC=y
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
+CONFIG_AUDIT_COMPAT_GENERIC=y
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_842_COMPRESS=m
+CONFIG_842_DECOMPRESS=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_COMPRESS=m
+CONFIG_LZ4HC_COMPRESS=m
+CONFIG_LZ4_DECOMPRESS=m
+CONFIG_ZSTD_COMMON=y
+CONFIG_ZSTD_COMPRESS=m
+CONFIG_ZSTD_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_MICROLZMA is not set
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_ZSTD=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_BTREE=y
+CONFIG_INTERVAL_TREE=y
+CONFIG_XARRAY_MULTI=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+CONFIG_DMA_OPS=y
+CONFIG_NEED_SG_DMA_FLAGS=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_DMA_DECLARE_COHERENT=y
+CONFIG_ARCH_HAS_SETUP_DMA_OPS=y
+CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y
+CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
+CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
+CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
+CONFIG_SWIOTLB=y
+# CONFIG_SWIOTLB_DYNAMIC is not set
+CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
+# CONFIG_DMA_RESTRICTED_POOL is not set
+CONFIG_DMA_NONCOHERENT_MMAP=y
+CONFIG_DMA_COHERENT_POOL=y
+CONFIG_DMA_DIRECT_REMAP=y
+# CONFIG_DMA_CMA is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_MAP_BENCHMARK is not set
+CONFIG_SGL_ALLOC=y
+CONFIG_CHECK_SIGNATURE=y
+# CONFIG_FORCE_NR_CPUS is not set
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+CONFIG_NLATTR=y
+CONFIG_CLZ_TAB=y
+CONFIG_IRQ_POLL=y
+CONFIG_MPILIB=y
+CONFIG_DIMLIB=y
+CONFIG_LIBFDT=y
+CONFIG_OID_REGISTRY=y
+CONFIG_UCS2_STRING=y
+CONFIG_HAVE_GENERIC_VDSO=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_VDSO_TIME_NS=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_SG_POOL=y
+CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_MEMREGION=y
+CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
+CONFIG_ARCH_STACKWALK=y
+CONFIG_STACKDEPOT=y
+CONFIG_SBITMAP=y
+CONFIG_PARMAN=m
+CONFIG_OBJAGG=m
+# end of Library routines
+
+CONFIG_GENERIC_IOREMAP=y
+CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
+CONFIG_PLDMFW=y
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_CALLER is not set
+# CONFIG_STACKTRACE_BUILD_ID is not set
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
+CONFIG_CONSOLE_LOGLEVEL_QUIET=4
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DYNAMIC_DEBUG_CORE=y
+CONFIG_SYMBOLIC_ERRNAME=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# end of printk and dmesg options
+
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_MISC=y
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_AS_HAS_NON_CONST_LEB128=y
+CONFIG_DEBUG_INFO_NONE=y
+# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+# CONFIG_DEBUG_INFO_DWARF5 is not set
+CONFIG_FRAME_WARN=2048
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_READABLE_ASM is not set
+# CONFIG_HEADERS_INSTALL is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_VMLINUX_MAP is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# end of Compile-time checks and compiler options
+
+#
+# Generic Kernel Debugging Instruments
+#
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
+CONFIG_MAGIC_SYSRQ_SERIAL=y
+CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ALLOW_ALL=y
+# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
+# CONFIG_DEBUG_FS_ALLOW_NONE is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_UBSAN is not set
+CONFIG_HAVE_ARCH_KCSAN=y
+CONFIG_HAVE_KCSAN_COMPILER=y
+# CONFIG_KCSAN is not set
+# end of Generic Kernel Debugging Instruments
+
+#
+# Networking Debugging
+#
+# CONFIG_NET_DEV_REFCNT_TRACKER is not set
+# CONFIG_NET_NS_REFCNT_TRACKER is not set
+# CONFIG_DEBUG_NET is not set
+# end of Networking Debugging
+
+#
+# Memory Debugging
+#
+CONFIG_PAGE_EXTENSION=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_PAGE_TABLE_CHECK is not set
+CONFIG_PAGE_POISONING=y
+# CONFIG_DEBUG_PAGE_REF is not set
+# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_ARCH_HAS_DEBUG_WX=y
+CONFIG_DEBUG_WX=y
+CONFIG_GENERIC_PTDUMP=y
+CONFIG_PTDUMP_CORE=y
+# CONFIG_PTDUMP_DEBUGFS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_PER_VMA_LOCK_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SHRINKER_DEBUG is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VM_PGTABLE is not set
+CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
+# CONFIG_DEBUG_VIRTUAL is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+CONFIG_HAVE_ARCH_KASAN=y
+CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
+CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y
+CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
+CONFIG_CC_HAS_KASAN_GENERIC=y
+CONFIG_CC_HAS_KASAN_SW_TAGS=y
+CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
+# CONFIG_KASAN is not set
+CONFIG_HAVE_ARCH_KFENCE=y
+# CONFIG_KFENCE is not set
+# end of Memory Debugging
+
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Oops, Lockups and Hangs
+#
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y
+CONFIG_HARDLOCKUP_DETECTOR=y
+# CONFIG_HARDLOCKUP_DETECTOR_PERF is not set
+CONFIG_HARDLOCKUP_DETECTOR_BUDDY=y
+# CONFIG_HARDLOCKUP_DETECTOR_ARCH is not set
+CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER=y
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+# CONFIG_WQ_WATCHDOG is not set
+# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set
+# CONFIG_TEST_LOCKUP is not set
+# end of Debug Oops, Lockups and Hangs
+
+#
+# Scheduler Debugging
+#
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHED_INFO=y
+CONFIG_SCHEDSTATS=y
+# end of Scheduler Debugging
+
+# CONFIG_DEBUG_TIMEKEEPING is not set
+CONFIG_DEBUG_PREEMPT=y
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_SCF_TORTURE_TEST is not set
+# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
+# end of Lock Debugging (spinlocks, mutexes, etc...)
+
+# CONFIG_DEBUG_IRQFLAGS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
+# CONFIG_DEBUG_KOBJECT is not set
+
+#
+# Debug kernel data structures
+#
+CONFIG_DEBUG_LIST=y
+# CONFIG_DEBUG_PLIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_MAPLE_TREE is not set
+# end of Debug kernel data structures
+
+#
+# RCU Debugging
+#
+# CONFIG_RCU_SCALE_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_REF_SCALE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
+# CONFIG_RCU_CPU_STALL_CPUTIME is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_EQS_DEBUG is not set
+# end of RCU Debugging
+
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
+# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_RETVAL=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_BOOTTIME_TRACING is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_HWLAT_TRACER is not set
+# CONFIG_OSNOISE_TRACER is not set
+# CONFIG_TIMERLAT_TRACER is not set
+# CONFIG_FTRACE_SYSCALLS is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_UPROBE_EVENTS=y
+CONFIG_BPF_EVENTS=y
+CONFIG_DYNAMIC_EVENTS=y
+CONFIG_PROBE_EVENTS=y
+# CONFIG_SYNTH_EVENTS is not set
+# CONFIG_USER_EVENTS is not set
+# CONFIG_HIST_TRIGGERS is not set
+# CONFIG_TRACE_EVENT_INJECT is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_TRACE_EVAL_MAP_FILE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
+# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
+# CONFIG_RV is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
+CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_IO_STRICT_DEVMEM=y
+
+#
+# arm64 Debugging
+#
+CONFIG_PID_IN_CONTEXTIDR=y
+# CONFIG_ARM64_RELOC_TEST is not set
+CONFIG_CORESIGHT=m
+CONFIG_CORESIGHT_LINKS_AND_SINKS=m
+# CONFIG_CORESIGHT_LINK_AND_SINK_TMC is not set
+# CONFIG_CORESIGHT_SINK_TPIU is not set
+# CONFIG_CORESIGHT_SINK_ETBV10 is not set
+CONFIG_CORESIGHT_SOURCE_ETM4X=m
+# CONFIG_ETM4X_IMPDEF_FEATURE is not set
+# CONFIG_CORESIGHT_STM is not set
+# CONFIG_CORESIGHT_CPU_DEBUG is not set
+# CONFIG_CORESIGHT_CTI is not set
+CONFIG_CORESIGHT_TRBE=m
+# CONFIG_ULTRASOC_SMB is not set
+# CONFIG_CORESIGHT_TPDM is not set
+# CONFIG_CORESIGHT_TPDA is not set
+# CONFIG_CORESIGHT_DUMMY is not set
+# end of arm64 Debugging
+
+#
+# Kernel Testing and Coverage
+#
+# CONFIG_KUNIT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_ARCH_HAS_KCOV=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+# CONFIG_KCOV is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_ARCH_USE_MEMTEST=y
+# CONFIG_MEMTEST is not set
+# CONFIG_HYPERV_TESTING is not set
+# end of Kernel Testing and Coverage
+
+#
+# Rust hacking
+#
+# end of Rust hacking
+# end of Kernel hacking
diff --git a/scripts/package-build/linux-kernel/arch/x86/configs/vyos_defconfig b/scripts/package-build/linux-kernel/arch/x86/configs/vyos_defconfig
new file mode 100644
index 00000000..de3b84aa
--- /dev/null
+++ b/scripts/package-build/linux-kernel/arch/x86/configs/vyos_defconfig
@@ -0,0 +1,6396 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/x86 6.6.89 Kernel Configuration
+#
+CONFIG_CC_VERSION_TEXT="gcc (Debian 12.2.0-14) 12.2.0"
+CONFIG_CC_IS_GCC=y
+CONFIG_GCC_VERSION=120200
+CONFIG_CLANG_VERSION=0
+CONFIG_AS_IS_GNU=y
+CONFIG_AS_VERSION=24000
+CONFIG_LD_IS_BFD=y
+CONFIG_LD_VERSION=24000
+CONFIG_LLD_VERSION=0
+CONFIG_CC_CAN_LINK=y
+CONFIG_CC_CAN_LINK_STATIC=y
+CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
+CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
+CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y
+CONFIG_TOOLS_SUPPORT_RELR=y
+CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
+CONFIG_PAHOLE_VERSION=124
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_TABLE_SORT=y
+CONFIG_THREAD_INFO_IN_TASK=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_WERROR is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_BUILD_SALT=""
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_ZSTD=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+CONFIG_KERNEL_XZ=y
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_ZSTD is not set
+CONFIG_DEFAULT_INIT=""
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_WATCH_QUEUE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_USELIB=y
+CONFIG_AUDIT=y
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_AUDITSYSCALL=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_INJECTION=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_IRQ_MSI_IOMMU=y
+CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
+CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+# CONFIG_GENERIC_IRQ_DEBUGFS is not set
+# end of IRQ subsystem
+
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_ARCH_CLOCKSOURCE_INIT=y
+CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+# CONFIG_NO_HZ_FULL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=100
+# end of Timers subsystem
+
+CONFIG_BPF=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
+
+#
+# BPF subsystem
+#
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_JIT=y
+# CONFIG_BPF_JIT_ALWAYS_ON is not set
+CONFIG_BPF_JIT_DEFAULT_ON=y
+# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
+# CONFIG_BPF_PRELOAD is not set
+# CONFIG_BPF_LSM is not set
+# end of BPF subsystem
+
+CONFIG_PREEMPT_NONE_BUILD=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_DYNAMIC is not set
+# CONFIG_SCHED_CORE is not set
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_PSI is not set
+# end of CPU/Task time and stats accounting
+
+CONFIG_CPU_ISOLATION=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_TREE_SRCU=y
+CONFIG_TASKS_RCU_GENERIC=y
+CONFIG_TASKS_TRACE_RCU=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_NEED_SEGCBLIST=y
+# end of RCU Subsystem
+
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_IKHEADERS is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_PRINTK_INDEX is not set
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+
+#
+# Scheduler features
+#
+# CONFIG_UCLAMP_TASK is not set
+# end of Scheduler features
+
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
+CONFIG_CC_HAS_INT128=y
+CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
+CONFIG_GCC10_NO_ARRAY_BOUNDS=y
+CONFIG_CC_NO_ARRAY_BOUNDS=y
+CONFIG_ARCH_SUPPORTS_INT128=y
+CONFIG_NUMA_BALANCING=y
+CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y
+CONFIG_CGROUPS=y
+CONFIG_PAGE_COUNTER=y
+# CONFIG_CGROUP_FAVOR_DYNMODS is not set
+CONFIG_MEMCG=y
+CONFIG_MEMCG_KMEM=y
+# CONFIG_BLK_CGROUP is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_SCHED_MM_CID=y
+CONFIG_CGROUP_PIDS=y
+# CONFIG_CGROUP_RDMA is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_HUGETLB is not set
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_CGROUP_PERF is not set
+CONFIG_CGROUP_BPF=y
+# CONFIG_CGROUP_MISC is not set
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_SOCK_CGROUP_DATA=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_TIME_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_RD_ZSTD=y
+# CONFIG_BOOT_CONFIG is not set
+CONFIG_INITRAMFS_PRESERVE_MTIME=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_LD_ORPHAN_WARN=y
+CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
+CONFIG_SYSCTL=y
+CONFIG_HAVE_UID16=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+CONFIG_MULTIUSER=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_FHANDLE=y
+CONFIG_POSIX_TIMERS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_FUTEX_PI=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_IO_URING is not set
+CONFIG_ADVISE_SYSCALLS=y
+CONFIG_MEMBARRIER=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_SELFTEST is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
+CONFIG_KALLSYMS_BASE_RELATIVE=y
+CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
+# CONFIG_KCMP is not set
+CONFIG_RSEQ=y
+CONFIG_CACHESTAT_SYSCALL=y
+# CONFIG_DEBUG_RSEQ is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_GUEST_PERF_EVENTS=y
+# CONFIG_PC104 is not set
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# end of Kernel Performance Events And Counters
+
+CONFIG_SYSTEM_DATA_VERIFICATION=y
+# CONFIG_PROFILING is not set
+CONFIG_TRACEPOINTS=y
+
+#
+# Kexec and crash features
+#
+CONFIG_CRASH_CORE=y
+CONFIG_KEXEC_CORE=y
+CONFIG_KEXEC=y
+# CONFIG_KEXEC_FILE is not set
+# CONFIG_CRASH_DUMP is not set
+# end of Kexec and crash features
+# end of General setup
+
+CONFIG_64BIT=y
+CONFIG_X86_64=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_OUTPUT_FORMAT="elf64-x86-64"
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_MMU=y
+CONFIG_ARCH_MMAP_RND_BITS_MIN=28
+CONFIG_ARCH_MMAP_RND_BITS_MAX=32
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_HAVE_INTEL_TXT=y
+CONFIG_X86_64_SMP=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_PGTABLE_LEVELS=4
+CONFIG_CC_HAS_SANE_STACKPROTECTOR=y
+
+#
+# Processor type and features
+#
+CONFIG_SMP=y
+CONFIG_X86_X2APIC=y
+CONFIG_X86_MPPARSE=y
+# CONFIG_GOLDFISH is not set
+# CONFIG_X86_CPU_RESCTRL is not set
+# CONFIG_X86_EXTENDED_PLATFORM is not set
+CONFIG_X86_INTEL_LPSS=y
+CONFIG_X86_AMD_PLATFORM_DEVICE=y
+CONFIG_IOSF_MBI=y
+# CONFIG_IOSF_MBI_DEBUG is not set
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_XXL=y
+# CONFIG_PARAVIRT_DEBUG is not set
+CONFIG_PARAVIRT_SPINLOCKS=y
+CONFIG_X86_HV_CALLBACK_VECTOR=y
+CONFIG_XEN=y
+CONFIG_XEN_PV=y
+CONFIG_XEN_512GB=y
+CONFIG_XEN_PV_SMP=y
+CONFIG_XEN_PV_DOM0=y
+CONFIG_XEN_PVHVM=y
+CONFIG_XEN_PVHVM_SMP=y
+CONFIG_XEN_PVHVM_GUEST=y
+CONFIG_XEN_SAVE_RESTORE=y
+# CONFIG_XEN_DEBUG_FS is not set
+CONFIG_XEN_PVH=y
+CONFIG_XEN_DOM0=y
+CONFIG_XEN_PV_MSR_SAFE=y
+CONFIG_KVM_GUEST=y
+CONFIG_ARCH_CPUIDLE_HALTPOLL=y
+CONFIG_PVH=y
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+CONFIG_PARAVIRT_CLOCK=y
+# CONFIG_JAILHOUSE_GUEST is not set
+# CONFIG_ACRN_GUEST is not set
+# CONFIG_INTEL_TDX_GUEST is not set
+# CONFIG_MK8 is not set
+# CONFIG_MPSC is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MATOM is not set
+CONFIG_GENERIC_CPU=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=64
+CONFIG_X86_DEBUGCTLMSR=y
+CONFIG_IA32_FEAT_CTL=y
+CONFIG_X86_VMX_FEATURE_NAMES=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_HYGON=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_ZHAOXIN=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+CONFIG_DMI=y
+CONFIG_GART_IOMMU=y
+CONFIG_BOOT_VESA_SUPPORT=y
+# CONFIG_MAXSMP is not set
+CONFIG_NR_CPUS_RANGE_BEGIN=2
+CONFIG_NR_CPUS_RANGE_END=512
+CONFIG_NR_CPUS_DEFAULT=64
+CONFIG_NR_CPUS=256
+CONFIG_SCHED_CLUSTER=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
+CONFIG_SCHED_MC_PRIO=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCELOG_LEGACY is not set
+CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_AMD=y
+CONFIG_X86_MCE_THRESHOLD=y
+# CONFIG_X86_MCE_INJECT is not set
+
+#
+# Performance monitoring
+#
+CONFIG_PERF_EVENTS_INTEL_UNCORE=m
+CONFIG_PERF_EVENTS_INTEL_RAPL=m
+CONFIG_PERF_EVENTS_INTEL_CSTATE=m
+CONFIG_PERF_EVENTS_AMD_POWER=m
+CONFIG_PERF_EVENTS_AMD_UNCORE=y
+# CONFIG_PERF_EVENTS_AMD_BRS is not set
+# end of Performance monitoring
+
+CONFIG_X86_16BIT=y
+CONFIG_X86_ESPFIX64=y
+CONFIG_X86_VSYSCALL_EMULATION=y
+CONFIG_X86_IOPL_IOPERM=y
+CONFIG_MICROCODE=y
+# CONFIG_MICROCODE_LATE_LOADING is not set
+CONFIG_X86_MSR=m
+CONFIG_X86_CPUID=m
+# CONFIG_X86_5LEVEL is not set
+CONFIG_X86_DIRECT_GBPAGES=y
+# CONFIG_X86_CPA_STATISTICS is not set
+# CONFIG_AMD_MEM_ENCRYPT is not set
+CONFIG_NUMA=y
+CONFIG_AMD_NUMA=y
+CONFIG_X86_64_ACPI_NUMA=y
+# CONFIG_NUMA_EMU is not set
+CONFIG_NODES_SHIFT=6
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_X86_PMEM_LEGACY_DEVICE=y
+CONFIG_X86_PMEM_LEGACY=m
+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
+CONFIG_MTRR=y
+CONFIG_MTRR_SANITIZER=y
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
+CONFIG_X86_PAT=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+CONFIG_X86_UMIP=y
+CONFIG_CC_HAS_IBT=y
+# CONFIG_X86_KERNEL_IBT is not set
+CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
+CONFIG_X86_INTEL_TSX_MODE_OFF=y
+# CONFIG_X86_INTEL_TSX_MODE_ON is not set
+# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
+# CONFIG_X86_SGX is not set
+# CONFIG_X86_USER_SHADOW_STACK is not set
+CONFIG_EFI=y
+CONFIG_EFI_STUB=y
+CONFIG_EFI_HANDOVER_PROTOCOL=y
+CONFIG_EFI_MIXED=y
+# CONFIG_EFI_FAKE_MEMMAP is not set
+CONFIG_EFI_RUNTIME_MAP=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_ARCH_SUPPORTS_KEXEC=y
+CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y
+CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY=y
+CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y
+CONFIG_ARCH_SUPPORTS_KEXEC_SIG_FORCE=y
+CONFIG_ARCH_SUPPORTS_KEXEC_BZIMAGE_VERIFY_SIG=y
+CONFIG_ARCH_SUPPORTS_KEXEC_JUMP=y
+CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y
+CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y
+CONFIG_PHYSICAL_START=0x1000000
+CONFIG_RELOCATABLE=y
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_X86_NEED_RELOCS=y
+CONFIG_PHYSICAL_ALIGN=0x200000
+CONFIG_DYNAMIC_MEMORY_LAYOUT=y
+CONFIG_RANDOMIZE_MEMORY=y
+CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_COMPAT_VDSO is not set
+# CONFIG_LEGACY_VSYSCALL_XONLY is not set
+CONFIG_LEGACY_VSYSCALL_NONE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MODIFY_LDT_SYSCALL=y
+# CONFIG_STRICT_SIGALTSTACK_SIZE is not set
+CONFIG_HAVE_LIVEPATCH=y
+# end of Processor type and features
+
+CONFIG_CC_HAS_SLS=y
+CONFIG_CC_HAS_RETURN_THUNK=y
+CONFIG_CC_HAS_ENTRY_PADDING=y
+CONFIG_FUNCTION_PADDING_CFI=11
+CONFIG_FUNCTION_PADDING_BYTES=16
+CONFIG_CALL_PADDING=y
+CONFIG_HAVE_CALL_THUNKS=y
+CONFIG_CALL_THUNKS=y
+CONFIG_PREFIX_SYMBOLS=y
+CONFIG_CPU_MITIGATIONS=y
+CONFIG_PAGE_TABLE_ISOLATION=y
+CONFIG_RETPOLINE=y
+CONFIG_RETHUNK=y
+CONFIG_CPU_UNRET_ENTRY=y
+CONFIG_CALL_DEPTH_TRACKING=y
+# CONFIG_CALL_THUNKS_DEBUG is not set
+CONFIG_CPU_IBPB_ENTRY=y
+CONFIG_CPU_IBRS_ENTRY=y
+CONFIG_CPU_SRSO=y
+# CONFIG_SLS is not set
+# CONFIG_GDS_FORCE_MITIGATION is not set
+CONFIG_MITIGATION_RFDS=y
+CONFIG_MITIGATION_SPECTRE_BHI=y
+CONFIG_ARCH_HAS_ADD_PAGES=y
+
+#
+# Power management and ACPI options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_HIBERNATE_CALLBACKS=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_CLK=y
+# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
+# CONFIG_ENERGY_MODEL is not set
+CONFIG_ARCH_SUPPORTS_ACPI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
+CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
+CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
+# CONFIG_ACPI_DEBUGGER is not set
+CONFIG_ACPI_SPCR_TABLE=y
+# CONFIG_ACPI_FPDT is not set
+CONFIG_ACPI_LPIT=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
+# CONFIG_ACPI_EC_DEBUGFS is not set
+# CONFIG_ACPI_AC is not set
+# CONFIG_ACPI_BATTERY is not set
+CONFIG_ACPI_BUTTON=m
+# CONFIG_ACPI_TINY_POWER_BUTTON is not set
+CONFIG_ACPI_FAN=m
+# CONFIG_ACPI_TAD is not set
+# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_CPU_FREQ_PSS=y
+CONFIG_ACPI_PROCESSOR_CSTATE=y
+CONFIG_ACPI_PROCESSOR_IDLE=y
+CONFIG_ACPI_CPPC_LIB=y
+CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_IPMI=m
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_ACPI_PROCESSOR_AGGREGATOR=m
+CONFIG_ACPI_THERMAL=m
+CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
+CONFIG_ACPI_TABLE_UPGRADE=y
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_ACPI_PCI_SLOT=y
+CONFIG_ACPI_CONTAINER=y
+CONFIG_ACPI_HOTPLUG_IOAPIC=y
+# CONFIG_ACPI_SBS is not set
+CONFIG_ACPI_HED=y
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+CONFIG_ACPI_BGRT=y
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+CONFIG_ACPI_NFIT=m
+# CONFIG_NFIT_SECURITY_DEBUG is not set
+CONFIG_ACPI_NUMA=y
+# CONFIG_ACPI_HMAT is not set
+CONFIG_HAVE_ACPI_APEI=y
+CONFIG_HAVE_ACPI_APEI_NMI=y
+CONFIG_ACPI_APEI=y
+CONFIG_ACPI_APEI_GHES=y
+CONFIG_ACPI_APEI_PCIEAER=y
+CONFIG_ACPI_APEI_MEMORY_FAILURE=y
+# CONFIG_ACPI_APEI_EINJ is not set
+# CONFIG_ACPI_APEI_ERST_DEBUG is not set
+# CONFIG_ACPI_DPTF is not set
+CONFIG_ACPI_EXTLOG=y
+CONFIG_ACPI_ADXL=y
+# CONFIG_ACPI_CONFIGFS is not set
+# CONFIG_ACPI_PFRUT is not set
+CONFIG_ACPI_PCC=y
+# CONFIG_ACPI_FFH is not set
+# CONFIG_PMIC_OPREGION is not set
+CONFIG_ACPI_PRMT=y
+CONFIG_X86_PM_TIMER=y
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=m
+CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+
+#
+# CPU frequency scaling drivers
+#
+CONFIG_X86_INTEL_PSTATE=y
+CONFIG_X86_PCC_CPUFREQ=m
+CONFIG_X86_AMD_PSTATE=y
+CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3
+# CONFIG_X86_AMD_PSTATE_UT is not set
+CONFIG_X86_ACPI_CPUFREQ=m
+CONFIG_X86_ACPI_CPUFREQ_CPB=y
+CONFIG_X86_POWERNOW_K8=m
+CONFIG_X86_AMD_FREQ_SENSITIVITY=m
+CONFIG_X86_SPEEDSTEP_CENTRINO=m
+CONFIG_X86_P4_CLOCKMOD=m
+
+#
+# shared options
+#
+CONFIG_X86_SPEEDSTEP_LIB=m
+# end of CPU Frequency scaling
+
+#
+# CPU Idle
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_CPU_IDLE_GOV_TEO is not set
+CONFIG_CPU_IDLE_GOV_HALTPOLL=y
+CONFIG_HALTPOLL_CPUIDLE=y
+# end of CPU Idle
+
+CONFIG_INTEL_IDLE=y
+# end of Power management and ACPI options
+
+#
+# Bus options (PCI etc.)
+#
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_XEN=y
+CONFIG_MMCONF_FAM10H=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_ISA_BUS is not set
+CONFIG_ISA_DMA_API=y
+CONFIG_AMD_NB=y
+# end of Bus options (PCI etc.)
+
+#
+# Binary Emulations
+#
+CONFIG_IA32_EMULATION=y
+# CONFIG_X86_X32_ABI is not set
+CONFIG_COMPAT_32=y
+CONFIG_COMPAT=y
+CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
+# end of Binary Emulations
+
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
+CONFIG_AS_AVX512=y
+CONFIG_AS_SHA1_NI=y
+CONFIG_AS_SHA256_NI=y
+CONFIG_AS_TPAUSE=y
+CONFIG_AS_GFNI=y
+CONFIG_AS_WRUSS=y
+CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y
+
+#
+# General architecture-dependent options
+#
+CONFIG_HOTPLUG_SMT=y
+CONFIG_HOTPLUG_CORE_SYNC=y
+CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
+CONFIG_HOTPLUG_CORE_SYNC_FULL=y
+CONFIG_HOTPLUG_SPLIT_STARTUP=y
+CONFIG_HOTPLUG_PARALLEL=y
+CONFIG_GENERIC_ENTRY=y
+# CONFIG_KPROBES is not set
+CONFIG_JUMP_LABEL=y
+# CONFIG_STATIC_KEYS_SELFTEST is not set
+# CONFIG_STATIC_CALL_SELFTEST is not set
+CONFIG_UPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
+CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
+CONFIG_HAVE_NMI=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
+CONFIG_ARCH_HAS_SET_MEMORY=y
+CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
+CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y
+CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
+CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
+CONFIG_ARCH_WANTS_NO_INSTR=y
+CONFIG_HAVE_ASM_MODVERSIONS=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_RSEQ=y
+CONFIG_HAVE_RUST=y
+CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
+CONFIG_MMU_GATHER_TABLE_FREE=y
+CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
+CONFIG_MMU_GATHER_MERGE_VMAS=y
+CONFIG_MMU_LAZY_TLB_REFCOUNT=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
+CONFIG_HAVE_ARCH_SECCOMP=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP=y
+CONFIG_SECCOMP_FILTER=y
+# CONFIG_SECCOMP_CACHE_DEBUG is not set
+CONFIG_HAVE_ARCH_STACKLEAK=y
+CONFIG_HAVE_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR=y
+CONFIG_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
+CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
+CONFIG_LTO_NONE=y
+CONFIG_ARCH_SUPPORTS_CFI_CLANG=y
+CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
+CONFIG_HAVE_CONTEXT_TRACKING_USER=y
+CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MOVE_PUD=y
+CONFIG_HAVE_MOVE_PMD=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_WANT_PMD_MKWRITE=y
+CONFIG_HAVE_ARCH_SOFT_DIRTY=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
+CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+CONFIG_HAVE_EXIT_THREAD=y
+CONFIG_ARCH_MMAP_RND_BITS=28
+CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
+CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_HAVE_OBJTOOL=y
+CONFIG_HAVE_JUMP_LABEL_HACK=y
+CONFIG_HAVE_NOINSTR_HACK=y
+CONFIG_HAVE_NOINSTR_VALIDATION=y
+CONFIG_HAVE_UACCESS_VALIDATION=y
+CONFIG_HAVE_STACK_VALIDATION=y
+CONFIG_HAVE_RELIABLE_STACKTRACE=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_COMPAT_OLD_SIGACTION=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_HAVE_ARCH_VMAP_STACK=y
+CONFIG_VMAP_STACK=y
+CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
+CONFIG_RANDOMIZE_KSTACK_OFFSET=y
+# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
+CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
+CONFIG_STRICT_MODULE_RWX=y
+CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
+CONFIG_ARCH_USE_MEMREMAP_PROT=y
+# CONFIG_LOCK_EVENT_COUNTS is not set
+CONFIG_ARCH_HAS_MEM_ENCRYPT=y
+CONFIG_HAVE_STATIC_CALL=y
+CONFIG_HAVE_STATIC_CALL_INLINE=y
+CONFIG_HAVE_PREEMPT_DYNAMIC=y
+CONFIG_HAVE_PREEMPT_DYNAMIC_CALL=y
+CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
+CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
+CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
+CONFIG_DYNAMIC_SIGFRAME=y
+CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+# end of GCOV-based kernel profiling
+
+CONFIG_HAVE_GCC_PLUGINS=y
+CONFIG_FUNCTION_ALIGNMENT_4B=y
+CONFIG_FUNCTION_ALIGNMENT_16B=y
+CONFIG_FUNCTION_ALIGNMENT=16
+# end of General architecture-dependent options
+
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULE_SIG_FORMAT=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_DEBUG is not set
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
+CONFIG_MODVERSIONS=y
+CONFIG_ASM_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_ALL=y
+# CONFIG_MODULE_SIG_SHA1 is not set
+# CONFIG_MODULE_SIG_SHA224 is not set
+# CONFIG_MODULE_SIG_SHA256 is not set
+# CONFIG_MODULE_SIG_SHA384 is not set
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_MODULE_SIG_HASH="sha512"
+CONFIG_MODULE_COMPRESS_NONE=y
+# CONFIG_MODULE_COMPRESS_GZIP is not set
+# CONFIG_MODULE_COMPRESS_XZ is not set
+# CONFIG_MODULE_COMPRESS_ZSTD is not set
+# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
+CONFIG_MODPROBE_PATH="/sbin/modprobe"
+# CONFIG_TRIM_UNUSED_KSYMS is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_BLOCK=y
+CONFIG_BLOCK_LEGACY_AUTOLOAD=y
+CONFIG_BLK_DEV_BSG_COMMON=y
+CONFIG_BLK_ICQ=y
+CONFIG_BLK_DEV_BSGLIB=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BLK_DEV_INTEGRITY_T10=y
+# CONFIG_BLK_DEV_ZONED is not set
+CONFIG_BLK_WBT=y
+CONFIG_BLK_WBT_MQ=y
+CONFIG_BLK_DEBUG_FS=y
+CONFIG_BLK_SED_OPAL=y
+# CONFIG_BLK_INLINE_ENCRYPTION is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# end of Partition Types
+
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_BLK_PM=y
+CONFIG_BLOCK_HOLDER_DEPRECATED=y
+CONFIG_BLK_MQ_STACKING=y
+
+#
+# IO Schedulers
+#
+CONFIG_MQ_IOSCHED_DEADLINE=y
+CONFIG_MQ_IOSCHED_KYBER=y
+CONFIG_IOSCHED_BFQ=y
+# end of IO Schedulers
+
+CONFIG_PADATA=y
+CONFIG_ASN1=y
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+CONFIG_INLINE_READ_UNLOCK=y
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+CONFIG_INLINE_WRITE_UNLOCK=y
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
+CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
+CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
+CONFIG_FREEZER=y
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_ELFCORE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BINFMT_MISC=m
+CONFIG_COREDUMP=y
+# end of Executable file formats
+
+#
+# Memory Management options
+#
+# CONFIG_SWAP is not set
+
+#
+# SLAB allocator options
+#
+# CONFIG_SLAB_DEPRECATED is not set
+CONFIG_SLUB=y
+# CONFIG_SLUB_TINY is not set
+CONFIG_SLAB_MERGE_DEFAULT=y
+CONFIG_SLAB_FREELIST_RANDOM=y
+CONFIG_SLAB_FREELIST_HARDENED=y
+# CONFIG_SLUB_STATS is not set
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_RANDOM_KMALLOC_CACHES is not set
+# end of SLAB allocator options
+
+# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=y
+CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y
+CONFIG_HAVE_FAST_GUP=y
+CONFIG_NUMA_KEEP_MEMINFO=y
+CONFIG_MEMORY_ISOLATION=y
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
+CONFIG_MEMORY_BALLOON=y
+CONFIG_BALLOON_COMPACTION=y
+CONFIG_COMPACTION=y
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+CONFIG_PAGE_REPORTING=y
+CONFIG_MIGRATION=y
+CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
+CONFIG_ARCH_ENABLE_THP_MIGRATION=y
+CONFIG_CONTIG_ALLOC=y
+CONFIG_PCP_BATCH_SCALE_MAX=5
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU_NOTIFIER=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+CONFIG_MEMORY_FAILURE=y
+# CONFIG_HWPOISON_INJECT is not set
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANTS_THP_SWAP=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
+CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
+# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
+# CONFIG_READ_ONLY_THP_FOR_FS is not set
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_USE_PERCPU_NUMA_NODE_ID=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_CMA=y
+# CONFIG_CMA_DEBUG is not set
+# CONFIG_CMA_DEBUGFS is not set
+# CONFIG_CMA_SYSFS is not set
+CONFIG_CMA_AREAS=19
+CONFIG_GENERIC_EARLY_IOREMAP=y
+# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
+# CONFIG_IDLE_PAGE_TRACKING is not set
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y
+CONFIG_ARCH_HAS_PTE_DEVMAP=y
+CONFIG_ARCH_HAS_ZONE_DMA_SET=y
+CONFIG_ZONE_DMA=y
+CONFIG_ZONE_DMA32=y
+CONFIG_HMM_MIRROR=y
+CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
+CONFIG_ARCH_HAS_PKEYS=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_PERCPU_STATS is not set
+# CONFIG_GUP_TEST is not set
+# CONFIG_DMAPOOL_TEST is not set
+CONFIG_ARCH_HAS_PTE_SPECIAL=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_SECRETMEM=y
+# CONFIG_ANON_VMA_NAME is not set
+CONFIG_USERFAULTFD=y
+CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
+CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
+CONFIG_PTE_MARKER_UFFD_WP=y
+# CONFIG_LRU_GEN is not set
+CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y
+CONFIG_PER_VMA_LOCK=y
+CONFIG_LOCK_MM_AND_FIND_VMA=y
+
+#
+# Data Access Monitoring
+#
+# CONFIG_DAMON is not set
+# end of Data Access Monitoring
+# end of Memory Management options
+
+CONFIG_NET=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_EGRESS=y
+CONFIG_NET_XGRESS=y
+CONFIG_NET_REDIRECT=y
+CONFIG_SKB_EXTENSIONS=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_DIAG=m
+CONFIG_UNIX=y
+CONFIG_UNIX_SCM=y
+CONFIG_AF_UNIX_OOB=y
+CONFIG_UNIX_DIAG=m
+CONFIG_TLS=y
+CONFIG_TLS_DEVICE=y
+# CONFIG_TLS_TOE is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_OFFLOAD=y
+CONFIG_XFRM_ALGO=m
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_USER_COMPAT is not set
+CONFIG_XFRM_INTERFACE=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_AH=m
+CONFIG_XFRM_ESP=m
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_XFRM_ESPINTCP=y
+# CONFIG_SMC is not set
+CONFIG_XDP_SOCKETS=y
+# CONFIG_XDP_SOCKETS_DIAG is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_FIB_TRIE_STATS=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IP_TUNNEL=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE_COMMON=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_NET_IPVTI=m
+CONFIG_NET_UDP_TUNNEL=m
+CONFIG_NET_FOU=m
+CONFIG_NET_FOU_IP_TUNNELS=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_ESP_OFFLOAD=m
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_TABLE_PERTURB_ORDER=16
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_INET_UDP_DIAG=m
+# CONFIG_INET_RAW_DIAG is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_NV=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_CONG_DCTCP=m
+CONFIG_TCP_CONG_CDG=m
+CONFIG_TCP_CONG_BBR=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_ESP_OFFLOAD=m
+CONFIG_INET6_ESPINTCP=y
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_ILA=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_FOU=m
+CONFIG_IPV6_FOU_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_IPV6_SEG6_LWTUNNEL=y
+CONFIG_IPV6_SEG6_HMAC=y
+CONFIG_IPV6_SEG6_BPF=y
+# CONFIG_IPV6_RPL_LWTUNNEL is not set
+# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
+# CONFIG_NETLABEL is not set
+CONFIG_MPTCP=y
+CONFIG_INET_MPTCP_DIAG=m
+CONFIG_MPTCP_IPV6=y
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PTP_CLASSIFY=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_EGRESS=y
+CONFIG_NETFILTER_SKIP_EGRESS=y
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_FAMILY_BRIDGE=y
+CONFIG_NETFILTER_FAMILY_ARP=y
+CONFIG_NETFILTER_BPF_LINK=y
+# CONFIG_NETFILTER_NETLINK_HOOK is not set
+CONFIG_NETFILTER_NETLINK_ACCT=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_NETLINK_OSF=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_LOG_SYSLOG=m
+CONFIG_NETFILTER_CONNCOUNT=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_LABELS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_GRE=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NF_CT_NETLINK_TIMEOUT=m
+CONFIG_NF_CT_NETLINK_HELPER=m
+CONFIG_NETFILTER_NETLINK_GLUE_CT=y
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_NAT_MASQUERADE=y
+CONFIG_NETFILTER_SYNPROXY=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_NETDEV=y
+CONFIG_NFT_NUMGEN=m
+CONFIG_NFT_CT=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NFT_CONNLIMIT=m
+CONFIG_NFT_LOG=m
+CONFIG_NFT_LIMIT=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_TUNNEL=m
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_QUOTA=m
+CONFIG_NFT_REJECT=m
+CONFIG_NFT_REJECT_INET=m
+CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
+CONFIG_NFT_FIB=m
+CONFIG_NFT_FIB_INET=m
+CONFIG_NFT_XFRM=m
+CONFIG_NFT_SOCKET=m
+CONFIG_NFT_OSF=m
+CONFIG_NFT_TPROXY=m
+CONFIG_NFT_SYNPROXY=m
+CONFIG_NF_DUP_NETDEV=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
+CONFIG_NFT_FIB_NETDEV=m
+# CONFIG_NFT_REJECT_NETDEV is not set
+CONFIG_NF_FLOW_TABLE_INET=m
+CONFIG_NF_FLOW_TABLE=m
+# CONFIG_NF_FLOW_TABLE_PROCFS is not set
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XTABLES_COMPAT=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+CONFIG_NETFILTER_XT_SET=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_AUDIT=m
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_HMARK=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_LED=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_NAT=m
+CONFIG_NETFILTER_XT_TARGET_NETMAP=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=m
+CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_BPF=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ECN=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_NFACCT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# end of Core Netfilter Configuration
+
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_IPMAC=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_FO=m
+CONFIG_IP_VS_OVF=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+# CONFIG_IP_VS_MH is not set
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+# CONFIG_IP_VS_TWOS is not set
+
+#
+# IPVS SH scheduler
+#
+CONFIG_IP_VS_SH_TAB_BITS=8
+
+#
+# IPVS MH scheduler
+#
+CONFIG_IP_VS_MH_TAB_INDEX=12
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PE_SIP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_SOCKET_IPV4=m
+CONFIG_NF_TPROXY_IPV4=m
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_REJECT_IPV4=m
+CONFIG_NFT_DUP_IPV4=m
+CONFIG_NFT_FIB_IPV4=m
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_DUP_IPV4=m
+CONFIG_NF_LOG_ARP=m
+CONFIG_NF_LOG_IPV4=m
+CONFIG_NF_REJECT_IPV4=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_RPFILTER=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_SYNPROXY=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_SECURITY is not set
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# end of IP: Netfilter Configuration
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_SOCKET_IPV6=m
+CONFIG_NF_TPROXY_IPV6=m
+CONFIG_NF_TABLES_IPV6=y
+CONFIG_NFT_REJECT_IPV6=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_NFT_FIB_IPV6=m
+CONFIG_NF_DUP_IPV6=m
+CONFIG_NF_REJECT_IPV6=m
+CONFIG_NF_LOG_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_SRH=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+# CONFIG_IP6_NF_SECURITY is not set
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+# end of IPv6: Netfilter Configuration
+
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_TABLES_BRIDGE=m
+# CONFIG_NFT_BRIDGE_META is not set
+CONFIG_NFT_BRIDGE_REJECT=m
+CONFIG_NF_CONNTRACK_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+# CONFIG_BPFILTER is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+# end of DCCP CCIDs Configuration
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# end of DCCP Kernel Hacking
+
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_OBJCNT is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
+CONFIG_SCTP_COOKIE_HMAC_MD5=y
+CONFIG_SCTP_COOKIE_HMAC_SHA1=y
+CONFIG_INET_SCTP_DIAG=m
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_MRP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_BRIDGE_VLAN_FILTERING=y
+# CONFIG_BRIDGE_MRP is not set
+# CONFIG_BRIDGE_CFM is not set
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFB=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_CBS=m
+CONFIG_NET_SCH_ETF=m
+CONFIG_NET_SCH_MQPRIO_LIB=m
+# CONFIG_NET_SCH_TAPRIO is not set
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+CONFIG_NET_SCH_MQPRIO=m
+CONFIG_NET_SCH_SKBPRIO=m
+CONFIG_NET_SCH_CHOKE=m
+CONFIG_NET_SCH_QFQ=m
+CONFIG_NET_SCH_CODEL=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_CAKE=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_NET_SCH_HHF=m
+CONFIG_NET_SCH_PIE=m
+# CONFIG_NET_SCH_FQ_PIE is not set
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_SCH_PLUG=m
+# CONFIG_NET_SCH_ETS is not set
+# CONFIG_NET_SCH_DEFAULT is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_CLS_MATCHALL=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_EMATCH_IPSET=m
+# CONFIG_NET_EMATCH_IPT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+# CONFIG_NET_ACT_SAMPLE is not set
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_NET_ACT_CSUM=m
+CONFIG_NET_ACT_MPLS=m
+CONFIG_NET_ACT_VLAN=m
+CONFIG_NET_ACT_BPF=m
+CONFIG_NET_ACT_CONNMARK=m
+# CONFIG_NET_ACT_CTINFO is not set
+CONFIG_NET_ACT_SKBMOD=m
+# CONFIG_NET_ACT_IFE is not set
+CONFIG_NET_ACT_TUNNEL_KEY=m
+# CONFIG_NET_ACT_CT is not set
+# CONFIG_NET_ACT_GATE is not set
+# CONFIG_NET_TC_SKB_EXT is not set
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+CONFIG_VSOCKETS=m
+CONFIG_VSOCKETS_DIAG=m
+CONFIG_VSOCKETS_LOOPBACK=m
+CONFIG_VMWARE_VMCI_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS=m
+CONFIG_VIRTIO_VSOCKETS_COMMON=m
+CONFIG_HYPERV_VSOCKETS=m
+CONFIG_NETLINK_DIAG=m
+CONFIG_MPLS=y
+CONFIG_NET_MPLS_GSO=y
+CONFIG_MPLS_ROUTING=m
+CONFIG_MPLS_IPTUNNEL=m
+# CONFIG_NET_NSH is not set
+CONFIG_HSR=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NET_L3_MASTER_DEV=y
+# CONFIG_QRTR is not set
+# CONFIG_NET_NCSI is not set
+CONFIG_PCPU_DEV_REFCNT=y
+CONFIG_MAX_SKB_FRAGS=17
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+CONFIG_XPS=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_NET_CLASSID=y
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_STREAM_PARSER is not set
+CONFIG_NET_FLOW_LIMIT=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_DROP_MONITOR=y
+# end of Network testing
+# end of Networking options
+
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AF_KCM is not set
+CONFIG_STREAM_PARSER=y
+# CONFIG_MCTP is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+CONFIG_CFG80211_CERTIFICATION_ONUS=y
+CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
+CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
+CONFIG_CFG80211_EXTRA_REGDB_KEYDIR=""
+# CONFIG_CFG80211_REG_CELLULAR_HINTS is not set
+# CONFIG_CFG80211_REG_RELAX_NO_IR is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+CONFIG_CFG80211_CRDA_SUPPORT=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_CFG80211_WEXT_EXPORT=y
+CONFIG_LIB80211=m
+CONFIG_LIB80211_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_RFKILL_GPIO is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+CONFIG_PSAMPLE=y
+# CONFIG_NET_IFE is not set
+CONFIG_LWTUNNEL=y
+CONFIG_LWTUNNEL_BPF=y
+CONFIG_DST_CACHE=y
+CONFIG_GRO_CELLS=y
+CONFIG_SOCK_VALIDATE_XMIT=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SOCK_MSG=y
+CONFIG_NET_DEVLINK=y
+CONFIG_PAGE_POOL=y
+# CONFIG_PAGE_POOL_STATS is not set
+CONFIG_FAILOVER=m
+CONFIG_ETHTOOL_NETLINK=y
+
+#
+# Device Drivers
+#
+CONFIG_HAVE_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEAER_INJECT=m
+# CONFIG_PCIE_ECRC is not set
+CONFIG_PCIEASPM=y
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_POWERSAVE is not set
+# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+CONFIG_PCIE_PME=y
+CONFIG_PCIE_DPC=y
+CONFIG_PCIE_PTM=y
+# CONFIG_PCIE_EDR is not set
+CONFIG_PCI_MSI=y
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_DEBUG is not set
+CONFIG_PCI_REALLOC_ENABLE_AUTO=y
+CONFIG_PCI_STUB=m
+# CONFIG_PCI_PF_STUB is not set
+CONFIG_XEN_PCIDEV_FRONTEND=m
+CONFIG_PCI_ATS=y
+CONFIG_PCI_LOCKLESS_CONFIG=y
+CONFIG_PCI_IOV=y
+CONFIG_PCI_PRI=y
+CONFIG_PCI_PASID=y
+CONFIG_PCI_LABEL=y
+CONFIG_PCI_HYPERV=m
+# CONFIG_PCIE_BUS_TUNE_OFF is not set
+CONFIG_PCIE_BUS_DEFAULT=y
+# CONFIG_PCIE_BUS_SAFE is not set
+# CONFIG_PCIE_BUS_PERFORMANCE is not set
+# CONFIG_PCIE_BUS_PEER2PEER is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_HOTPLUG_PCI=y
+CONFIG_HOTPLUG_PCI_ACPI=y
+CONFIG_HOTPLUG_PCI_ACPI_IBM=m
+CONFIG_HOTPLUG_PCI_CPCI=y
+CONFIG_HOTPLUG_PCI_CPCI_ZT5550=m
+CONFIG_HOTPLUG_PCI_CPCI_GENERIC=m
+CONFIG_HOTPLUG_PCI_SHPC=y
+
+#
+# PCI controller drivers
+#
+CONFIG_VMD=m
+CONFIG_PCI_HYPERV_INTERFACE=m
+
+#
+# Cadence-based PCIe controllers
+#
+# end of Cadence-based PCIe controllers
+
+#
+# DesignWare-based PCIe controllers
+#
+# CONFIG_PCI_MESON is not set
+# CONFIG_PCIE_DW_PLAT_HOST is not set
+# end of DesignWare-based PCIe controllers
+
+#
+# Mobiveil-based PCIe controllers
+#
+# end of Mobiveil-based PCIe controllers
+# end of PCI controller drivers
+
+#
+# PCI Endpoint
+#
+# CONFIG_PCI_ENDPOINT is not set
+# end of PCI Endpoint
+
+#
+# PCI switch controller drivers
+#
+# CONFIG_PCI_SW_SWITCHTEC is not set
+# end of PCI switch controller drivers
+
+# CONFIG_CXL_BUS is not set
+# CONFIG_PCCARD is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_AUXILIARY_BUS=y
+# CONFIG_UEVENT_HELPER is not set
+CONFIG_DEVTMPFS=y
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DEVTMPFS_SAFE is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
+# Firmware loader
+#
+CONFIG_FW_LOADER=y
+CONFIG_FW_LOADER_DEBUG=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_FW_LOADER_USER_HELPER=y
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+# CONFIG_FW_LOADER_COMPRESS is not set
+CONFIG_FW_CACHE=y
+# CONFIG_FW_UPLOAD is not set
+# end of Firmware loader
+
+CONFIG_WANT_DEV_COREDUMP=y
+CONFIG_ALLOW_DEV_COREDUMP=y
+CONFIG_DEV_COREDUMP=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
+# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
+CONFIG_SYS_HYPERVISOR=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_DMA_SHARED_BUFFER=y
+# CONFIG_DMA_FENCE_TRACE is not set
+# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set
+# end of Generic Driver Options
+
+#
+# Bus devices
+#
+# CONFIG_MHI_BUS is not set
+# CONFIG_MHI_BUS_EP is not set
+# end of Bus devices
+
+#
+# Cache Drivers
+#
+# end of Cache Drivers
+
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+
+#
+# Firmware Drivers
+#
+
+#
+# ARM System Control and Management Interface Protocol
+#
+# end of ARM System Control and Management Interface Protocol
+
+CONFIG_EDD=m
+# CONFIG_EDD_OFF is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_DMIID=y
+CONFIG_DMI_SYSFS=y
+CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
+# CONFIG_ISCSI_IBFT is not set
+# CONFIG_FW_CFG_SYSFS is not set
+CONFIG_SYSFB=y
+# CONFIG_SYSFB_SIMPLEFB is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# EFI (Extensible Firmware Interface) Support
+#
+CONFIG_EFI_ESRT=y
+CONFIG_EFI_VARS_PSTORE=m
+# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set
+CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
+CONFIG_EFI_RUNTIME_WRAPPERS=y
+# CONFIG_EFI_BOOTLOADER_CONTROL is not set
+# CONFIG_EFI_CAPSULE_LOADER is not set
+# CONFIG_EFI_TEST is not set
+CONFIG_EFI_DEV_PATH_PARSER=y
+CONFIG_APPLE_PROPERTIES=y
+# CONFIG_RESET_ATTACK_MITIGATION is not set
+# CONFIG_EFI_RCI2_TABLE is not set
+# CONFIG_EFI_DISABLE_PCI_DMA is not set
+CONFIG_EFI_EARLYCON=y
+CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y
+# CONFIG_EFI_DISABLE_RUNTIME is not set
+# CONFIG_EFI_COCO_SECRET is not set
+# end of EFI (Extensible Firmware Interface) Support
+
+CONFIG_UEFI_CPER=y
+CONFIG_UEFI_CPER_X86=y
+
+#
+# Tegra firmware driver
+#
+# end of Tegra firmware driver
+# end of Firmware Drivers
+
+# CONFIG_GNSS is not set
+# CONFIG_MTD is not set
+# CONFIG_OF is not set
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_PARPORT=y
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_1284 is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+
+#
+# Protocols
+#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_NULL_BLK=m
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_CDROM=m
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_ZRAM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_XEN_BLKDEV_FRONTEND=m
+CONFIG_XEN_BLKDEV_BACKEND=m
+CONFIG_VIRTIO_BLK=m
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_UBLK is not set
+
+#
+# NVME Support
+#
+CONFIG_NVME_CORE=y
+CONFIG_BLK_DEV_NVME=y
+CONFIG_NVME_MULTIPATH=y
+# CONFIG_NVME_VERBOSE_ERRORS is not set
+CONFIG_NVME_HWMON=y
+# CONFIG_NVME_RDMA is not set
+# CONFIG_NVME_FC is not set
+# CONFIG_NVME_TCP is not set
+# CONFIG_NVME_AUTH is not set
+# CONFIG_NVME_TARGET is not set
+# end of NVME Support
+
+#
+# Misc devices
+#
+CONFIG_SENSORS_LIS3LV02D=m
+CONFIG_AD525X_DPOT=m
+CONFIG_AD525X_DPOT_I2C=m
+# CONFIG_DUMMY_IRQ is not set
+CONFIG_IBM_ASM=m
+CONFIG_PHANTOM=m
+CONFIG_TIFM_CORE=m
+CONFIG_TIFM_7XX1=m
+CONFIG_ICS932S401=m
+CONFIG_ENCLOSURE_SERVICES=m
+CONFIG_HP_ILO=m
+CONFIG_APDS9802ALS=m
+CONFIG_ISL29003=m
+CONFIG_ISL29020=m
+CONFIG_SENSORS_TSL2550=m
+CONFIG_SENSORS_BH1770=m
+CONFIG_SENSORS_APDS990X=m
+CONFIG_HMC6352=m
+CONFIG_DS1682=m
+CONFIG_VMWARE_BALLOON=m
+# CONFIG_SRAM is not set
+# CONFIG_DW_XDATA_PCIE is not set
+# CONFIG_PCI_ENDPOINT_TEST is not set
+# CONFIG_XILINX_SDFEC is not set
+CONFIG_MISC_RTSX=m
+CONFIG_C2PORT=m
+CONFIG_C2PORT_DURAMAR_2150=m
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+CONFIG_EEPROM_LEGACY=m
+CONFIG_EEPROM_MAX6875=m
+CONFIG_EEPROM_93CX6=m
+# CONFIG_EEPROM_IDT_89HPESX is not set
+# CONFIG_EEPROM_EE1004 is not set
+# end of EEPROM support
+
+CONFIG_CB710_CORE=m
+# CONFIG_CB710_DEBUG is not set
+CONFIG_CB710_DEBUG_ASSUMPTIONS=y
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# end of Texas Instruments shared transport line discipline
+
+CONFIG_SENSORS_LIS3_I2C=m
+CONFIG_ALTERA_STAPL=m
+CONFIG_INTEL_MEI=m
+CONFIG_INTEL_MEI_ME=m
+# CONFIG_INTEL_MEI_TXE is not set
+CONFIG_VMWARE_VMCI=m
+# CONFIG_GENWQE is not set
+# CONFIG_ECHO is not set
+# CONFIG_BCM_VK is not set
+# CONFIG_MISC_ALCOR_PCI is not set
+CONFIG_MISC_RTSX_PCI=m
+CONFIG_MISC_RTSX_USB=m
+# CONFIG_UACCE is not set
+# CONFIG_PVPANIC is not set
+# CONFIG_GP_PCI1XXXX is not set
+# end of Misc devices
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI_COMMON=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_NETLINK=y
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=m
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_ENCLOSURE is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SAS_ATA=y
+CONFIG_SCSI_SAS_HOST_SMP=y
+CONFIG_SCSI_SRP_ATTRS=m
+# end of SCSI Transports
+
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_BNX2X_FCOE=m
+CONFIG_BE2ISCSI=m
+CONFIG_BLK_DEV_3W_XXXX_RAID=m
+CONFIG_SCSI_HPSA=m
+CONFIG_SCSI_3W_9XXX=m
+CONFIG_SCSI_3W_SAS=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AACRAID=m
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC94XX=m
+# CONFIG_AIC94XX_DEBUG is not set
+CONFIG_SCSI_MVSAS=m
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVSAS_TASKLET is not set
+CONFIG_SCSI_MVUMI=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_ARCMSR=m
+CONFIG_SCSI_ESAS2R=m
+CONFIG_MEGARAID_NEWGEN=y
+CONFIG_MEGARAID_MM=m
+CONFIG_MEGARAID_MAILBOX=m
+CONFIG_MEGARAID_LEGACY=m
+CONFIG_MEGARAID_SAS=m
+CONFIG_SCSI_MPT3SAS=m
+CONFIG_SCSI_MPT2SAS_MAX_SGE=128
+CONFIG_SCSI_MPT3SAS_MAX_SGE=128
+CONFIG_SCSI_MPT2SAS=m
+# CONFIG_SCSI_MPI3MR is not set
+CONFIG_SCSI_SMARTPQI=m
+CONFIG_SCSI_HPTIOP=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_FLASHPOINT is not set
+# CONFIG_SCSI_MYRB is not set
+# CONFIG_SCSI_MYRS is not set
+CONFIG_VMWARE_PVSCSI=m
+CONFIG_XEN_SCSI_FRONTEND=m
+CONFIG_HYPERV_STORAGE=m
+CONFIG_LIBFC=m
+CONFIG_LIBFCOE=m
+CONFIG_FCOE=m
+CONFIG_FCOE_FNIC=m
+CONFIG_SCSI_SNIC=m
+# CONFIG_SCSI_SNIC_DEBUG_FS is not set
+CONFIG_SCSI_DMX3191D=m
+# CONFIG_SCSI_FDOMAIN_PCI is not set
+CONFIG_SCSI_ISCI=m
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_STEX=m
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
+CONFIG_SCSI_QLOGIC_1280=m
+CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
+# CONFIG_QEDI is not set
+# CONFIG_QEDF is not set
+CONFIG_SCSI_LPFC=m
+# CONFIG_SCSI_LPFC_DEBUG_FS is not set
+CONFIG_SCSI_DC395x=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_WD719X=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_PMCRAID=m
+CONFIG_SCSI_PM8001=m
+CONFIG_SCSI_BFA_FC=m
+CONFIG_SCSI_VIRTIO=m
+CONFIG_SCSI_CHELSIO_FCOE=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+# end of SCSI device support
+
+CONFIG_ATA=m
+CONFIG_SATA_HOST=y
+CONFIG_PATA_TIMINGS=y
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_ATA_FORCE=y
+CONFIG_ATA_ACPI=y
+CONFIG_SATA_ZPODD=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=m
+CONFIG_SATA_MOBILE_LPM_POLICY=3
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_AHCI_DWC is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+CONFIG_PDC_ADMA=m
+CONFIG_SATA_QSTOR=m
+CONFIG_SATA_SX4=m
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+CONFIG_ATA_PIIX=m
+# CONFIG_SATA_DWC is not set
+CONFIG_SATA_MV=m
+CONFIG_SATA_NV=m
+CONFIG_SATA_PROMISE=m
+CONFIG_SATA_SIL=m
+CONFIG_SATA_SIS=m
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+CONFIG_SATA_VIA=m
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+CONFIG_PATA_OLDPIIX=m
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+CONFIG_PATA_SCH=m
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_SIL680=m
+CONFIG_PATA_SIS=m
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+CONFIG_PATA_VIA=m
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+CONFIG_PATA_MPIIX=m
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_PATA_ACPI is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_BITMAP_FILE=y
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID10=y
+CONFIG_MD_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_BCACHE is not set
+CONFIG_BLK_DEV_DM_BUILTIN=y
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_BUFIO=y
+# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
+# CONFIG_DM_UNSTRIPED is not set
+CONFIG_DM_CRYPT=y
+CONFIG_DM_SNAPSHOT=y
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_WRITECACHE is not set
+# CONFIG_DM_EBS is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_CLONE is not set
+# CONFIG_DM_MIRROR is not set
+CONFIG_DM_RAID=y
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_DUST is not set
+CONFIG_DM_INIT=y
+CONFIG_DM_UEVENT=y
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_LOG_WRITES is not set
+# CONFIG_DM_INTEGRITY is not set
+# CONFIG_DM_AUDIT is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=m
+CONFIG_FUSION_FC=m
+CONFIG_FUSION_SAS=m
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_CTL=m
+# CONFIG_FUSION_LOGGING is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# end of IEEE 1394 (FireWire) support
+
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=m
+CONFIG_NET_CORE=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
+# CONFIG_WIREGUARD_DEBUG is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_FC is not set
+CONFIG_IFB=m
+CONFIG_NET_TEAM=m
+CONFIG_NET_TEAM_MODE_BROADCAST=m
+CONFIG_NET_TEAM_MODE_ROUNDROBIN=m
+CONFIG_NET_TEAM_MODE_RANDOM=m
+CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m
+CONFIG_NET_TEAM_MODE_LOADBALANCE=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_IPVLAN_L3S=y
+CONFIG_IPVLAN=m
+CONFIG_IPVTAP=m
+CONFIG_VXLAN=m
+CONFIG_GENEVE=m
+# CONFIG_BAREUDP is not set
+CONFIG_GTP=m
+# CONFIG_AMT is not set
+CONFIG_MACSEC=m
+# CONFIG_NETCONSOLE is not set
+CONFIG_TUN=m
+CONFIG_TAP=m
+# CONFIG_TUN_VNET_CROSS_LE is not set
+CONFIG_VETH=m
+CONFIG_VIRTIO_NET=m
+CONFIG_NLMON=m
+CONFIG_NET_VRF=y
+# CONFIG_VSOCKMON is not set
+# CONFIG_ARCNET is not set
+CONFIG_ETHERNET=y
+CONFIG_MDIO=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_ET131X=m
+CONFIG_NET_VENDOR_ALACRITECH=y
+# CONFIG_SLICOSS is not set
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_ALTERA_TSE is not set
+CONFIG_NET_VENDOR_AMAZON=y
+CONFIG_ENA_ETHERNET=m
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_AMD8111_ETH=m
+CONFIG_PCNET32=m
+CONFIG_AMD_XGBE=m
+# CONFIG_AMD_XGBE_DCB is not set
+CONFIG_AMD_XGBE_HAVE_ECC=y
+# CONFIG_PDS_CORE is not set
+CONFIG_NET_VENDOR_AQUANTIA=y
+CONFIG_AQTION=m
+# CONFIG_NET_VENDOR_ARC is not set
+CONFIG_NET_VENDOR_ASIX=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_ATL2=m
+CONFIG_ATL1=m
+CONFIG_ATL1E=m
+CONFIG_ATL1C=m
+CONFIG_ALX=m
+# CONFIG_CX_ECAT is not set
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_B44=m
+CONFIG_B44_PCI_AUTOSELECT=y
+CONFIG_B44_PCICORE_AUTOSELECT=y
+CONFIG_B44_PCI=y
+# CONFIG_BCMGENET is not set
+CONFIG_BNX2=m
+CONFIG_CNIC=m
+CONFIG_TIGON3=m
+CONFIG_TIGON3_HWMON=y
+CONFIG_BNX2X=m
+CONFIG_BNX2X_SRIOV=y
+# CONFIG_SYSTEMPORT is not set
+CONFIG_BNXT=m
+CONFIG_BNXT_SRIOV=y
+CONFIG_BNXT_FLOWER_OFFLOAD=y
+# CONFIG_BNXT_DCB is not set
+CONFIG_BNXT_HWMON=y
+CONFIG_NET_VENDOR_CADENCE=y
+# CONFIG_MACB is not set
+CONFIG_NET_VENDOR_CAVIUM=y
+# CONFIG_THUNDER_NIC_PF is not set
+# CONFIG_THUNDER_NIC_VF is not set
+# CONFIG_THUNDER_NIC_BGX is not set
+# CONFIG_THUNDER_NIC_RGX is not set
+CONFIG_CAVIUM_PTP=y
+CONFIG_LIQUIDIO_CORE=m
+CONFIG_LIQUIDIO=m
+# CONFIG_LIQUIDIO_VF is not set
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_CHELSIO_T1=m
+CONFIG_CHELSIO_T1_1G=y
+CONFIG_CHELSIO_T3=m
+CONFIG_CHELSIO_T4=m
+# CONFIG_CHELSIO_T4_DCB is not set
+CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_LIB=m
+CONFIG_CHELSIO_INLINE_CRYPTO=y
+# CONFIG_CHELSIO_IPSEC_INLINE is not set
+# CONFIG_CHELSIO_TLS_DEVICE is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_CORTINA is not set
+CONFIG_NET_VENDOR_DAVICOM=y
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_DEC is not set
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_DL2K=m
+CONFIG_SUNDANCE=m
+# CONFIG_SUNDANCE_MMIO is not set
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_BE2NET=m
+CONFIG_BE2NET_HWMON=y
+CONFIG_BE2NET_BE2=y
+CONFIG_BE2NET_BE3=y
+CONFIG_BE2NET_LANCER=y
+CONFIG_BE2NET_SKYHAWK=y
+CONFIG_NET_VENDOR_ENGLEDER=y
+# CONFIG_TSNEP is not set
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_FUNGIBLE=y
+# CONFIG_FUN_ETH is not set
+CONFIG_NET_VENDOR_GOOGLE=y
+CONFIG_GVE=m
+CONFIG_NET_VENDOR_HUAWEI=y
+CONFIG_HINIC=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_E100=m
+CONFIG_E1000=m
+CONFIG_E1000E=m
+CONFIG_E1000E_HWTS=y
+CONFIG_IGB=m
+CONFIG_IGB_HWMON=y
+CONFIG_IGB_DCA=y
+CONFIG_IGBVF=m
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+CONFIG_I40E=m
+# CONFIG_I40E_DCB is not set
+CONFIG_IAVF=m
+CONFIG_I40EVF=m
+CONFIG_ICE=m
+CONFIG_ICE_SWITCHDEV=y
+CONFIG_ICE_HWTS=y
+# CONFIG_FM10K is not set
+CONFIG_IGC=m
+CONFIG_JME=m
+CONFIG_NET_VENDOR_LITEX=y
+CONFIG_NET_VENDOR_MARVELL=y
+# CONFIG_MVMDIO is not set
+CONFIG_SKGE=m
+# CONFIG_SKGE_DEBUG is not set
+CONFIG_SKGE_GENESIS=y
+CONFIG_SKY2=m
+# CONFIG_SKY2_DEBUG is not set
+# CONFIG_OCTEON_EP is not set
+# CONFIG_PRESTERA is not set
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_MLX4_EN=m
+CONFIG_MLX4_EN_DCB=y
+CONFIG_MLX4_CORE=m
+CONFIG_MLX4_DEBUG=y
+CONFIG_MLX4_CORE_GEN2=y
+CONFIG_MLX5_CORE=m
+# CONFIG_MLX5_FPGA is not set
+CONFIG_MLX5_CORE_EN=y
+CONFIG_MLX5_EN_ARFS=y
+CONFIG_MLX5_EN_RXNFC=y
+CONFIG_MLX5_MPFS=y
+CONFIG_MLX5_ESWITCH=y
+CONFIG_MLX5_BRIDGE=y
+CONFIG_MLX5_CORE_EN_DCB=y
+# CONFIG_MLX5_CORE_IPOIB is not set
+# CONFIG_MLX5_MACSEC is not set
+CONFIG_MLX5_EN_IPSEC=y
+CONFIG_MLX5_EN_TLS=y
+CONFIG_MLX5_SW_STEERING=y
+# CONFIG_MLX5_SF is not set
+CONFIG_MLXSW_CORE=m
+CONFIG_MLXSW_CORE_HWMON=y
+CONFIG_MLXSW_CORE_THERMAL=y
+CONFIG_MLXSW_PCI=m
+CONFIG_MLXSW_I2C=m
+CONFIG_MLXSW_SPECTRUM=m
+CONFIG_MLXSW_SPECTRUM_DCB=y
+CONFIG_MLXSW_MINIMAL=m
+CONFIG_MLXFW=m
+CONFIG_NET_VENDOR_MICREL=y
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_KSZ884X_PCI=m
+CONFIG_NET_VENDOR_MICROCHIP=y
+# CONFIG_LAN743X is not set
+# CONFIG_VCAP is not set
+CONFIG_NET_VENDOR_MICROSEMI=y
+CONFIG_NET_VENDOR_MICROSOFT=y
+# CONFIG_MICROSOFT_MANA is not set
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_MYRI10GE=m
+CONFIG_MYRI10GE_DCA=y
+CONFIG_FEALNX=m
+# CONFIG_NET_VENDOR_NI is not set
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NATSEMI=m
+CONFIG_NS83820=m
+CONFIG_NET_VENDOR_NETERION=y
+CONFIG_S2IO=m
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_8390 is not set
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_FORCEDETH=m
+CONFIG_NET_VENDOR_OKI=y
+# CONFIG_ETHOC is not set
+CONFIG_NET_VENDOR_PACKET_ENGINES=y
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+# CONFIG_NET_VENDOR_PENSANDO is not set
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+CONFIG_QLCNIC_SRIOV=y
+CONFIG_QLCNIC_DCB=y
+CONFIG_QLCNIC_HWMON=y
+CONFIG_NETXEN_NIC=m
+CONFIG_QED=m
+CONFIG_QED_SRIOV=y
+CONFIG_QEDE=m
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_BNA=m
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RDC is not set
+CONFIG_NET_VENDOR_REALTEK=y
+# CONFIG_ATP is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_R8169=m
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+# CONFIG_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_SC92031=m
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_SIS900=m
+CONFIG_SIS190=m
+CONFIG_NET_VENDOR_SOLARFLARE=y
+CONFIG_SFC=m
+CONFIG_SFC_MCDI_MON=y
+CONFIG_SFC_SRIOV=y
+CONFIG_SFC_MCDI_LOGGING=y
+CONFIG_SFC_FALCON=m
+# CONFIG_SFC_SIENA is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_STMMAC_ETH=m
+# CONFIG_STMMAC_SELFTESTS is not set
+CONFIG_STMMAC_PLATFORM=m
+CONFIG_DWMAC_GENERIC=m
+CONFIG_DWMAC_INTEL=m
+CONFIG_STMMAC_PCI=m
+# CONFIG_NET_VENDOR_SUN is not set
+CONFIG_NET_VENDOR_SYNOPSYS=y
+# CONFIG_DWC_XLGMAC is not set
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_TEHUTI=m
+CONFIG_NET_VENDOR_TI=y
+# CONFIG_TI_CPSW_PHY_SEL is not set
+CONFIG_TLAN=m
+CONFIG_NET_VENDOR_VERTEXCOM=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+CONFIG_VIA_VELOCITY=m
+CONFIG_NET_VENDOR_WANGXUN=y
+# CONFIG_NGBE is not set
+# CONFIG_TXGBE is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_NET_SB1000 is not set
+CONFIG_PHYLINK=m
+CONFIG_PHYLIB=y
+CONFIG_SWPHY=y
+# CONFIG_LED_TRIGGER_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_SFP is not set
+
+#
+# MII PHY device drivers
+#
+CONFIG_AMD_PHY=m
+# CONFIG_ADIN_PHY is not set
+# CONFIG_ADIN1100_PHY is not set
+CONFIG_AQUANTIA_PHY=m
+CONFIG_AX88796B_PHY=m
+CONFIG_BROADCOM_PHY=m
+# CONFIG_BCM54140_PHY is not set
+CONFIG_BCM7XXX_PHY=m
+# CONFIG_BCM84881_PHY is not set
+CONFIG_BCM87XX_PHY=m
+CONFIG_BCM_NET_PHYLIB=m
+CONFIG_CICADA_PHY=m
+CONFIG_CORTINA_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_INTEL_XWAY_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_MARVELL_10G_PHY=m
+# CONFIG_MARVELL_88Q2XXX_PHY is not set
+# CONFIG_MARVELL_88X2222_PHY is not set
+# CONFIG_MAXLINEAR_GPHY is not set
+# CONFIG_MEDIATEK_GE_PHY is not set
+CONFIG_MICREL_PHY=m
+# CONFIG_MICROCHIP_T1S_PHY is not set
+CONFIG_MICROCHIP_PHY=m
+CONFIG_MICROCHIP_T1_PHY=m
+CONFIG_MICROSEMI_PHY=m
+# CONFIG_MOTORCOMM_PHY is not set
+CONFIG_NATIONAL_PHY=m
+# CONFIG_NXP_CBTX_PHY is not set
+# CONFIG_NXP_C45_TJA11XX_PHY is not set
+# CONFIG_NXP_TJA11XX_PHY is not set
+# CONFIG_NCN26000_PHY is not set
+CONFIG_AT803X_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_RENESAS_PHY=m
+CONFIG_ROCKCHIP_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_STE10XP=m
+CONFIG_TERANETICS_PHY=m
+CONFIG_DP83822_PHY=m
+CONFIG_DP83TC811_PHY=m
+CONFIG_DP83848_PHY=m
+CONFIG_DP83867_PHY=m
+# CONFIG_DP83869_PHY is not set
+# CONFIG_DP83TD510_PHY is not set
+CONFIG_VITESSE_PHY=m
+# CONFIG_XILINX_GMII2RGMII is not set
+# CONFIG_PSE_CONTROLLER is not set
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_BUS=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_ACPI_MDIO=y
+CONFIG_MDIO_DEVRES=y
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_MVUSB is not set
+# CONFIG_MDIO_MSCC_MIIM is not set
+# CONFIG_MDIO_THUNDER is not set
+
+#
+# MDIO Multiplexers
+#
+
+#
+# PCS device drivers
+#
+CONFIG_PCS_XPCS=m
+# end of PCS device drivers
+
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+# CONFIG_PPPOE_HASH_BITS_1 is not set
+# CONFIG_PPPOE_HASH_BITS_2 is not set
+CONFIG_PPPOE_HASH_BITS_4=y
+# CONFIG_PPPOE_HASH_BITS_8 is not set
+CONFIG_PPPOE_HASH_BITS=4
+CONFIG_PPTP=m
+CONFIG_PPPOL2TP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_USB_NET_DRIVERS=m
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=m
+CONFIG_USB_RTL8152=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_AX88179_178A=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_HUAWEI_CDC_NCM=m
+CONFIG_USB_NET_CDC_MBIM=m
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_KALMIA is not set
+CONFIG_USB_NET_QMI_WWAN=m
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_USB_SIERRA_NET=m
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_NET_CH9200 is not set
+# CONFIG_USB_NET_AQC111 is not set
+CONFIG_USB_RTL8153_ECM=m
+CONFIG_WLAN=y
+CONFIG_WLAN_VENDOR_ADMTEK=y
+CONFIG_ADM8211=m
+CONFIG_ATH_COMMON=m
+CONFIG_WLAN_VENDOR_ATH=y
+# CONFIG_ATH_DEBUG is not set
+CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS=y
+CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING=y
+CONFIG_ATH5K=m
+# CONFIG_ATH5K_DEBUG is not set
+# CONFIG_ATH5K_TRACER is not set
+CONFIG_ATH5K_PCI=y
+# CONFIG_ATH5K_TEST_CHANNELS is not set
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_COMMON=m
+# CONFIG_ATH9K_BTCOEX_SUPPORT is not set
+CONFIG_ATH9K=m
+CONFIG_ATH9K_PCI=y
+# CONFIG_ATH9K_AHB is not set
+# CONFIG_ATH9K_DEBUGFS is not set
+# CONFIG_ATH9K_DFS_CERTIFIED is not set
+# CONFIG_ATH9K_DYNACK is not set
+# CONFIG_ATH9K_WOW is not set
+CONFIG_ATH9K_RFKILL=y
+CONFIG_ATH9K_CHANNEL_CONTEXT=y
+CONFIG_ATH9K_PCOEM=y
+# CONFIG_ATH9K_PCI_NO_EEPROM is not set
+CONFIG_ATH9K_HTC=m
+# CONFIG_ATH9K_HTC_DEBUGFS is not set
+# CONFIG_ATH9K_HWRNG is not set
+CONFIG_CARL9170=m
+CONFIG_CARL9170_LEDS=y
+CONFIG_CARL9170_WPC=y
+# CONFIG_CARL9170_HWRNG is not set
+CONFIG_ATH6KL=m
+CONFIG_ATH6KL_SDIO=m
+CONFIG_ATH6KL_USB=m
+# CONFIG_ATH6KL_DEBUG is not set
+# CONFIG_ATH6KL_TRACING is not set
+# CONFIG_ATH6KL_REGDOMAIN is not set
+CONFIG_AR5523=m
+CONFIG_WIL6210=m
+CONFIG_WIL6210_ISR_COR=y
+# CONFIG_WIL6210_TRACING is not set
+CONFIG_WIL6210_DEBUGFS=y
+CONFIG_ATH10K=m
+CONFIG_ATH10K_CE=y
+CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K_SDIO=m
+CONFIG_ATH10K_USB=m
+# CONFIG_ATH10K_DEBUG is not set
+# CONFIG_ATH10K_DEBUGFS is not set
+# CONFIG_ATH10K_TRACING is not set
+CONFIG_ATH10K_DFS_CERTIFIED=y
+# CONFIG_WCN36XX is not set
+# CONFIG_ATH11K is not set
+# CONFIG_ATH12K is not set
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+CONFIG_WLAN_VENDOR_BROADCOM=y
+CONFIG_B43=m
+CONFIG_B43_BCMA=y
+CONFIG_B43_SSB=y
+CONFIG_B43_BUSES_BCMA_AND_SSB=y
+# CONFIG_B43_BUSES_BCMA is not set
+# CONFIG_B43_BUSES_SSB is not set
+CONFIG_B43_PCI_AUTOSELECT=y
+CONFIG_B43_PCICORE_AUTOSELECT=y
+CONFIG_B43_SDIO=y
+CONFIG_B43_BCMA_PIO=y
+CONFIG_B43_PIO=y
+CONFIG_B43_PHY_G=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_PHY_HT=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+# CONFIG_B43LEGACY is not set
+CONFIG_BRCMUTIL=m
+CONFIG_BRCMSMAC=m
+CONFIG_BRCMFMAC=m
+CONFIG_BRCMFMAC_PROTO_BCDC=y
+CONFIG_BRCMFMAC_PROTO_MSGBUF=y
+CONFIG_BRCMFMAC_SDIO=y
+CONFIG_BRCMFMAC_USB=y
+CONFIG_BRCMFMAC_PCIE=y
+# CONFIG_BRCM_TRACING is not set
+# CONFIG_BRCMDBG is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+CONFIG_WLAN_VENDOR_INTEL=y
+# CONFIG_IPW2100 is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW2200_RADIOTAP=y
+CONFIG_IPW2200_PROMISCUOUS=y
+CONFIG_IPW2200_QOS=y
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_LIBIPW=m
+# CONFIG_LIBIPW_DEBUG is not set
+CONFIG_IWLEGACY=m
+CONFIG_IWL4965=m
+CONFIG_IWL3945=m
+
+#
+# iwl3945 / iwl4965 Debugging Options
+#
+# CONFIG_IWLEGACY_DEBUG is not set
+# end of iwl3945 / iwl4965 Debugging Options
+
+CONFIG_IWLWIFI=m
+CONFIG_IWLWIFI_LEDS=y
+CONFIG_IWLDVM=m
+CONFIG_IWLMVM=m
+CONFIG_IWLWIFI_OPMODE_MODULAR=y
+
+#
+# Debugging Options
+#
+# CONFIG_IWLWIFI_DEBUG is not set
+CONFIG_IWLWIFI_DEVICE_TRACING=y
+# end of Debugging Options
+
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+CONFIG_WLAN_VENDOR_MARVELL=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+CONFIG_LIBERTAS_MESH=y
+CONFIG_LIBERTAS_THINFIRM=m
+# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
+CONFIG_LIBERTAS_THINFIRM_USB=m
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
+CONFIG_MWIFIEX_PCIE=m
+CONFIG_MWIFIEX_USB=m
+CONFIG_MWL8K=m
+CONFIG_WLAN_VENDOR_MEDIATEK=y
+CONFIG_MT7601U=m
+CONFIG_MT76_CORE=m
+CONFIG_MT76_LEDS=y
+CONFIG_MT76_USB=m
+CONFIG_MT76_SDIO=m
+CONFIG_MT76x02_LIB=m
+CONFIG_MT76x02_USB=m
+CONFIG_MT76_CONNAC_LIB=m
+CONFIG_MT76x0_COMMON=m
+CONFIG_MT76x0U=m
+CONFIG_MT76x0E=m
+CONFIG_MT76x2_COMMON=m
+CONFIG_MT76x2E=m
+CONFIG_MT76x2U=m
+CONFIG_MT7603E=m
+CONFIG_MT7615_COMMON=m
+CONFIG_MT7615E=m
+CONFIG_MT7663_USB_SDIO_COMMON=m
+CONFIG_MT7663U=m
+CONFIG_MT7663S=m
+CONFIG_MT7915E=m
+# CONFIG_MT7921E is not set
+# CONFIG_MT7921S is not set
+# CONFIG_MT7921U is not set
+# CONFIG_MT7996E is not set
+CONFIG_WLAN_VENDOR_MICROCHIP=y
+# CONFIG_WILC1000_SDIO is not set
+CONFIG_WLAN_VENDOR_PURELIFI=y
+# CONFIG_PLFXLC is not set
+CONFIG_WLAN_VENDOR_RALINK=y
+CONFIG_RT2X00=m
+CONFIG_RT2400PCI=m
+CONFIG_RT2500PCI=m
+CONFIG_RT61PCI=m
+CONFIG_RT2800PCI=m
+CONFIG_RT2800PCI_RT33XX=y
+CONFIG_RT2800PCI_RT35XX=y
+CONFIG_RT2800PCI_RT53XX=y
+CONFIG_RT2800PCI_RT3290=y
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+CONFIG_RT2800USB_RT3573=y
+CONFIG_RT2800USB_RT53XX=y
+CONFIG_RT2800USB_RT55XX=y
+# CONFIG_RT2800USB_UNKNOWN is not set
+CONFIG_RT2800_LIB=m
+CONFIG_RT2800_LIB_MMIO=m
+CONFIG_RT2X00_LIB_MMIO=m
+CONFIG_RT2X00_LIB_PCI=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_WLAN_VENDOR_REALTEK=y
+CONFIG_RTL8180=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+CONFIG_RTL_CARDS=m
+CONFIG_RTL8192CE=m
+CONFIG_RTL8192SE=m
+CONFIG_RTL8192DE=m
+CONFIG_RTL8723AE=m
+CONFIG_RTL8723BE=m
+CONFIG_RTL8188EE=m
+CONFIG_RTL8192EE=m
+CONFIG_RTL8821AE=m
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTLWIFI_PCI=m
+CONFIG_RTLWIFI_USB=m
+# CONFIG_RTLWIFI_DEBUG is not set
+CONFIG_RTL8192C_COMMON=m
+CONFIG_RTL8723_COMMON=m
+CONFIG_RTLBTCOEXIST=m
+CONFIG_RTL8XXXU=m
+# CONFIG_RTL8XXXU_UNTESTED is not set
+# CONFIG_RTW88 is not set
+# CONFIG_RTW89 is not set
+CONFIG_WLAN_VENDOR_RSI=y
+CONFIG_RSI_91X=m
+CONFIG_RSI_DEBUGFS=y
+CONFIG_RSI_SDIO=m
+CONFIG_RSI_USB=m
+CONFIG_WLAN_VENDOR_SILABS=y
+# CONFIG_WFX is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+# CONFIG_WLAN_VENDOR_QUANTENNA is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+CONFIG_MAC80211_HWSIM=m
+# CONFIG_VIRT_WIFI is not set
+# CONFIG_WAN is not set
+
+#
+# Wireless WAN
+#
+# CONFIG_WWAN is not set
+# end of Wireless WAN
+
+CONFIG_XEN_NETDEV_FRONTEND=m
+CONFIG_XEN_NETDEV_BACKEND=m
+CONFIG_VMXNET3=m
+# CONFIG_FUJITSU_ES is not set
+CONFIG_USB4_NET=m
+CONFIG_HYPERV_NET=m
+# CONFIG_NETDEVSIM is not set
+CONFIG_NET_FAILOVER=m
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_SPARSEKMAP=m
+# CONFIG_INPUT_MATRIXKMAP is not set
+CONFIG_INPUT_VIVALDIFMAP=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT1050 is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_DLINK_DIR685 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO_POLLED=m
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PINEPHONE is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_CYPRESS_SF is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+CONFIG_INPUT_PCSPKR=m
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_DECODER is not set
+# CONFIG_INPUT_GPIO_VIBRA is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+# CONFIG_INPUT_AXP20X_PEK is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_DA7280_HAPTICS is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_IBM_PANEL is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_IQS269A is not set
+# CONFIG_INPUT_IQS626A is not set
+# CONFIG_INPUT_IQS7222 is not set
+# CONFIG_INPUT_CMA3000 is not set
+CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2665_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_RMI4_CORE is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+CONFIG_HYPERV_KEYBOARD=m
+# CONFIG_SERIO_GPIO_PS2 is not set
+# CONFIG_USERIO is not set
+# CONFIG_GAMEPORT is not set
+# end of Hardware I/O ports
+# end of Input device support
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_LEGACY_TIOCSTI=y
+CONFIG_LDISC_AUTOLOAD=y
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_EARLYCON=y
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_PNP=y
+# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
+CONFIG_SERIAL_8250_FINTEK=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DMA=y
+CONFIG_SERIAL_8250_PCILIB=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_EXAR=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+# CONFIG_SERIAL_8250_PCI1XXXX is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_SERIAL_8250_DWLIB=y
+CONFIG_SERIAL_8250_DW=y
+# CONFIG_SERIAL_8250_RT288X is not set
+# CONFIG_SERIAL_8250_LPSS is not set
+CONFIG_SERIAL_8250_MID=y
+CONFIG_SERIAL_8250_PERICOM=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_JSM=m
+# CONFIG_SERIAL_LANTIQ is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_ARC is not set
+CONFIG_SERIAL_RP2=m
+CONFIG_SERIAL_RP2_NR_UARTS=32
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_FSL_LINFLEXUART is not set
+# CONFIG_SERIAL_SPRD is not set
+# end of Serial drivers
+
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_MOXA_INTELLIO=m
+CONFIG_MOXA_SMARTIO=m
+CONFIG_N_HDLC=m
+CONFIG_N_GSM=m
+CONFIG_NOZOMI=m
+# CONFIG_NULL_TTY is not set
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_XEN=y
+CONFIG_HVC_XEN_FRONTEND=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
+CONFIG_TTY_PRINTK=m
+CONFIG_TTY_PRINTK_LEVEL=6
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_VIRTIO_CONSOLE=m
+CONFIG_IPMI_HANDLER=m
+CONFIG_IPMI_DMI_DECODE=y
+CONFIG_IPMI_PLAT_DATA=y
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=m
+CONFIG_IPMI_SI=m
+# CONFIG_IPMI_SSIF is not set
+# CONFIG_IPMI_IPMB is not set
+CONFIG_IPMI_WATCHDOG=m
+CONFIG_IPMI_POWEROFF=m
+# CONFIG_SSIF_IPMI_BMC is not set
+# CONFIG_IPMB_DEVICE_INTERFACE is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HW_RANDOM_INTEL=m
+CONFIG_HW_RANDOM_AMD=m
+# CONFIG_HW_RANDOM_BA431 is not set
+CONFIG_HW_RANDOM_VIA=m
+CONFIG_HW_RANDOM_VIRTIO=m
+# CONFIG_HW_RANDOM_XIPHERA is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_MWAVE is not set
+CONFIG_DEVMEM=y
+CONFIG_NVRAM=m
+CONFIG_DEVPORT=y
+CONFIG_HPET=y
+CONFIG_HPET_MMAP=y
+CONFIG_HPET_MMAP_DEFAULT=y
+CONFIG_HANGCHECK_TIMER=m
+CONFIG_TCG_TPM=m
+CONFIG_HW_RANDOM_TPM=y
+CONFIG_TCG_TIS_CORE=m
+CONFIG_TCG_TIS=m
+# CONFIG_TCG_TIS_I2C is not set
+# CONFIG_TCG_TIS_I2C_CR50 is not set
+CONFIG_TCG_TIS_I2C_ATMEL=m
+CONFIG_TCG_TIS_I2C_INFINEON=m
+CONFIG_TCG_TIS_I2C_NUVOTON=m
+CONFIG_TCG_NSC=m
+CONFIG_TCG_ATMEL=m
+CONFIG_TCG_INFINEON=m
+CONFIG_TCG_XEN=m
+CONFIG_TCG_CRB=m
+# CONFIG_TCG_VTPM_PROXY is not set
+CONFIG_TCG_TIS_ST33ZP24=m
+CONFIG_TCG_TIS_ST33ZP24_I2C=m
+# CONFIG_TELCLOCK is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XILLYUSB is not set
+# end of Character devices
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_ACPI_I2C_OPREGION=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MUX=m
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_LTC4306 is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+# CONFIG_I2C_MUX_REG is not set
+# CONFIG_I2C_MUX_MLXCPLD is not set
+# end of Multiplexer I2C Chip support
+
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_SMBUS=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ALGOPCA=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+CONFIG_I2C_CCGX_UCSI=m
+CONFIG_I2C_ALI1535=m
+CONFIG_I2C_ALI1563=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_AMD756=m
+CONFIG_I2C_AMD756_S4882=m
+CONFIG_I2C_AMD8111=m
+# CONFIG_I2C_AMD_MP2 is not set
+CONFIG_I2C_I801=m
+CONFIG_I2C_ISCH=m
+CONFIG_I2C_ISMT=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_CHT_WC=m
+CONFIG_I2C_NFORCE2=m
+CONFIG_I2C_NFORCE2_S4985=m
+# CONFIG_I2C_NVIDIA_GPU is not set
+CONFIG_I2C_SIS5595=m
+CONFIG_I2C_SIS630=m
+CONFIG_I2C_SIS96X=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_VIAPRO=m
+
+#
+# ACPI drivers
+#
+CONFIG_I2C_SCMI=m
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CBUS_GPIO is not set
+CONFIG_I2C_DESIGNWARE_CORE=y
+# CONFIG_I2C_DESIGNWARE_SLAVE is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set
+CONFIG_I2C_DESIGNWARE_PCI=m
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_KEMPLD=m
+CONFIG_I2C_OCORES=m
+CONFIG_I2C_PCA_PLATFORM=m
+CONFIG_I2C_SIMTEC=m
+CONFIG_I2C_XILINX=m
+
+#
+# External I2C/SMBus adapter drivers
+#
+CONFIG_I2C_DIOLAN_U2C=m
+# CONFIG_I2C_CP2615 is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PCI1XXXX is not set
+CONFIG_I2C_ROBOTFUZZ_OSIF=m
+CONFIG_I2C_TAOS_EVM=m
+CONFIG_I2C_TINY_USB=m
+CONFIG_I2C_VIPERBOARD=m
+
+#
+# Other I2C/SMBus bus drivers
+#
+CONFIG_I2C_MLXCPLD=m
+# CONFIG_I2C_VIRTIO is not set
+# end of I2C Hardware Bus support
+
+CONFIG_I2C_STUB=m
+CONFIG_I2C_SLAVE=y
+CONFIG_I2C_SLAVE_EEPROM=m
+# CONFIG_I2C_SLAVE_TESTUNIT is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# end of I2C support
+
+# CONFIG_I3C is not set
+# CONFIG_SPI is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+CONFIG_PPS=y
+# CONFIG_PPS_DEBUG is not set
+
+#
+# PPS clients support
+#
+# CONFIG_PPS_CLIENT_KTIMER is not set
+CONFIG_PPS_CLIENT_LDISC=m
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PTP_1588_CLOCK_KVM=y
+# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
+# CONFIG_PTP_1588_CLOCK_IDTCM is not set
+# CONFIG_PTP_1588_CLOCK_MOCK is not set
+# CONFIG_PTP_1588_CLOCK_VMW is not set
+# end of PTP clock support
+
+CONFIG_PINCTRL=y
+CONFIG_PINMUX=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+# CONFIG_DEBUG_PINCTRL is not set
+CONFIG_PINCTRL_AMD=y
+# CONFIG_PINCTRL_CY8C95X0 is not set
+# CONFIG_PINCTRL_MCP23S08 is not set
+# CONFIG_PINCTRL_SX150X is not set
+
+#
+# Intel pinctrl drivers
+#
+CONFIG_PINCTRL_BAYTRAIL=y
+CONFIG_PINCTRL_CHERRYVIEW=y
+# CONFIG_PINCTRL_LYNXPOINT is not set
+CONFIG_PINCTRL_INTEL=y
+# CONFIG_PINCTRL_ALDERLAKE is not set
+CONFIG_PINCTRL_BROXTON=y
+# CONFIG_PINCTRL_CANNONLAKE is not set
+# CONFIG_PINCTRL_CEDARFORK is not set
+# CONFIG_PINCTRL_DENVERTON is not set
+# CONFIG_PINCTRL_ELKHARTLAKE is not set
+# CONFIG_PINCTRL_EMMITSBURG is not set
+# CONFIG_PINCTRL_GEMINILAKE is not set
+# CONFIG_PINCTRL_ICELAKE is not set
+# CONFIG_PINCTRL_JASPERLAKE is not set
+# CONFIG_PINCTRL_LAKEFIELD is not set
+# CONFIG_PINCTRL_LEWISBURG is not set
+# CONFIG_PINCTRL_METEORLAKE is not set
+CONFIG_PINCTRL_SUNRISEPOINT=y
+# CONFIG_PINCTRL_TIGERLAKE is not set
+# end of Intel pinctrl drivers
+
+#
+# Renesas pinctrl drivers
+#
+# end of Renesas pinctrl drivers
+
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_FASTPATH_LIMIT=512
+CONFIG_GPIO_ACPI=y
+CONFIG_GPIOLIB_IRQCHIP=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_CDEV_V1=y
+CONFIG_GPIO_GENERIC=m
+
+#
+# Memory mapped GPIO drivers
+#
+CONFIG_GPIO_AMDPT=m
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_EXAR is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_MB86S7X is not set
+CONFIG_GPIO_AMD_FCH=m
+# end of Memory mapped GPIO drivers
+
+#
+# Port-mapped I/O GPIO drivers
+#
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_GPIO_F7188X is not set
+# CONFIG_GPIO_IT87 is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_WINBOND is not set
+# CONFIG_GPIO_WS16C48 is not set
+# end of Port-mapped I/O GPIO drivers
+
+#
+# I2C GPIO expanders
+#
+# CONFIG_GPIO_FXL6408 is not set
+# CONFIG_GPIO_DS4520 is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCA9570 is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_TPIC2810 is not set
+# end of I2C GPIO expanders
+
+#
+# MFD GPIO expanders
+#
+# CONFIG_GPIO_ELKHARTLAKE is not set
+CONFIG_GPIO_KEMPLD=m
+# end of MFD GPIO expanders
+
+#
+# PCI GPIO expanders
+#
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_BT8XX is not set
+CONFIG_GPIO_ML_IOH=m
+# CONFIG_GPIO_PCI_IDIO_16 is not set
+# CONFIG_GPIO_PCIE_IDIO_24 is not set
+# CONFIG_GPIO_RDC321X is not set
+# end of PCI GPIO expanders
+
+#
+# USB GPIO expanders
+#
+CONFIG_GPIO_VIPERBOARD=m
+# end of USB GPIO expanders
+
+#
+# Virtual GPIO drivers
+#
+# CONFIG_GPIO_AGGREGATOR is not set
+# CONFIG_GPIO_LATCH is not set
+# CONFIG_GPIO_MOCKUP is not set
+# CONFIG_GPIO_VIRTIO is not set
+# CONFIG_GPIO_SIM is not set
+# end of Virtual GPIO drivers
+
+CONFIG_W1=m
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+CONFIG_W1_MASTER_MATROX=m
+CONFIG_W1_MASTER_DS2490=m
+CONFIG_W1_MASTER_DS2482=m
+CONFIG_W1_MASTER_GPIO=m
+# CONFIG_W1_MASTER_SGI is not set
+# end of 1-wire Bus Masters
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=m
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2405=m
+CONFIG_W1_SLAVE_DS2408=m
+CONFIG_W1_SLAVE_DS2408_READBACK=y
+CONFIG_W1_SLAVE_DS2413=m
+CONFIG_W1_SLAVE_DS2406=m
+CONFIG_W1_SLAVE_DS2423=m
+CONFIG_W1_SLAVE_DS2805=m
+# CONFIG_W1_SLAVE_DS2430 is not set
+CONFIG_W1_SLAVE_DS2431=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+CONFIG_W1_SLAVE_DS2438=m
+# CONFIG_W1_SLAVE_DS250X is not set
+CONFIG_W1_SLAVE_DS2780=m
+CONFIG_W1_SLAVE_DS2781=m
+CONFIG_W1_SLAVE_DS28E04=m
+CONFIG_W1_SLAVE_DS28E17=m
+# end of 1-wire Slaves
+
+# CONFIG_POWER_RESET is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_POWER_SUPPLY_HWMON=y
+# CONFIG_IP5XXX_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_CHARGER_ADP5061 is not set
+# CONFIG_BATTERY_CW2015 is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SAMSUNG_SDI is not set
+CONFIG_BATTERY_SBS=m
+# CONFIG_CHARGER_SBS is not set
+# CONFIG_MANAGER_SBS is not set
+CONFIG_BATTERY_BQ27XXX=m
+# CONFIG_BATTERY_BQ27XXX_I2C is not set
+CONFIG_BATTERY_BQ27XXX_HDQ=m
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_MAX17042=m
+# CONFIG_BATTERY_MAX1721X is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_LT3651 is not set
+# CONFIG_CHARGER_LTC4162L is not set
+# CONFIG_CHARGER_MAX77976 is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24257 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ2515X is not set
+# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_BQ25980 is not set
+# CONFIG_CHARGER_BQ256XX is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_RT5033 is not set
+# CONFIG_CHARGER_RT9455 is not set
+# CONFIG_CHARGER_RT9467 is not set
+# CONFIG_CHARGER_RT9471 is not set
+# CONFIG_CHARGER_BD99954 is not set
+# CONFIG_BATTERY_UG3105 is not set
+CONFIG_HWMON=y
+CONFIG_HWMON_VID=m
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+CONFIG_SENSORS_ABITUGURU=m
+CONFIG_SENSORS_ABITUGURU3=m
+CONFIG_SENSORS_AD7414=m
+CONFIG_SENSORS_AD7418=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+# CONFIG_SENSORS_ADM1177 is not set
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_ADT7X10=m
+CONFIG_SENSORS_ADT7410=m
+CONFIG_SENSORS_ADT7411=m
+CONFIG_SENSORS_ADT7462=m
+CONFIG_SENSORS_ADT7470=m
+CONFIG_SENSORS_ADT7475=m
+# CONFIG_SENSORS_AHT10 is not set
+# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set
+# CONFIG_SENSORS_AS370 is not set
+CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
+CONFIG_SENSORS_K8TEMP=m
+CONFIG_SENSORS_K10TEMP=m
+CONFIG_SENSORS_FAM15H_POWER=m
+CONFIG_SENSORS_APPLESMC=m
+CONFIG_SENSORS_ASB100=m
+CONFIG_SENSORS_ATXP1=m
+# CONFIG_SENSORS_CORSAIR_CPRO is not set
+# CONFIG_SENSORS_CORSAIR_PSU is not set
+CONFIG_SENSORS_DRIVETEMP=m
+CONFIG_SENSORS_DS620=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_DELL_SMM=m
+# CONFIG_I8K is not set
+CONFIG_SENSORS_I5K_AMB=m
+CONFIG_SENSORS_F71805F=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_F75375S=m
+CONFIG_SENSORS_FSCHMD=m
+CONFIG_SENSORS_FTSTEUTATES=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_G760A=m
+CONFIG_SENSORS_G762=m
+CONFIG_SENSORS_HIH6130=m
+# CONFIG_SENSORS_HS3001 is not set
+CONFIG_SENSORS_IBMAEM=m
+CONFIG_SENSORS_IBMPEX=m
+CONFIG_SENSORS_I5500=m
+CONFIG_SENSORS_CORETEMP=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_JC42=m
+CONFIG_SENSORS_POWR1220=m
+CONFIG_SENSORS_LINEAGE=m
+CONFIG_SENSORS_LTC2945=m
+# CONFIG_SENSORS_LTC2947_I2C is not set
+CONFIG_SENSORS_LTC2990=m
+# CONFIG_SENSORS_LTC2992 is not set
+CONFIG_SENSORS_LTC4151=m
+CONFIG_SENSORS_LTC4215=m
+CONFIG_SENSORS_LTC4222=m
+CONFIG_SENSORS_LTC4245=m
+CONFIG_SENSORS_LTC4260=m
+CONFIG_SENSORS_LTC4261=m
+# CONFIG_SENSORS_MAX127 is not set
+CONFIG_SENSORS_MAX16065=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_MAX1668=m
+CONFIG_SENSORS_MAX197=m
+# CONFIG_SENSORS_MAX31730 is not set
+# CONFIG_SENSORS_MAX31760 is not set
+# CONFIG_MAX31827 is not set
+# CONFIG_SENSORS_MAX6620 is not set
+CONFIG_SENSORS_MAX6621=m
+CONFIG_SENSORS_MAX6639=m
+CONFIG_SENSORS_MAX6650=m
+CONFIG_SENSORS_MAX6697=m
+CONFIG_SENSORS_MAX31790=m
+# CONFIG_SENSORS_MC34VR500 is not set
+CONFIG_SENSORS_MCP3021=m
+CONFIG_SENSORS_TC654=m
+# CONFIG_SENSORS_TPS23861 is not set
+CONFIG_SENSORS_MENF21BMC_HWMON=m
+# CONFIG_SENSORS_MR75203 is not set
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_LM93=m
+CONFIG_SENSORS_LM95234=m
+CONFIG_SENSORS_LM95241=m
+CONFIG_SENSORS_LM95245=m
+CONFIG_SENSORS_PC87360=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_NCT6683=m
+CONFIG_SENSORS_NCT6775_CORE=m
+CONFIG_SENSORS_NCT6775=m
+# CONFIG_SENSORS_NCT6775_I2C is not set
+CONFIG_SENSORS_NCT7802=m
+CONFIG_SENSORS_NCT7904=m
+CONFIG_SENSORS_NPCM7XX=m
+# CONFIG_SENSORS_NZXT_KRAKEN2 is not set
+# CONFIG_SENSORS_NZXT_SMART2 is not set
+# CONFIG_SENSORS_OCC_P8_I2C is not set
+# CONFIG_SENSORS_OXP is not set
+CONFIG_SENSORS_PCF8591=m
+CONFIG_PMBUS=m
+CONFIG_SENSORS_PMBUS=m
+# CONFIG_SENSORS_ACBEL_FSG032 is not set
+# CONFIG_SENSORS_ADM1266 is not set
+CONFIG_SENSORS_ADM1275=m
+# CONFIG_SENSORS_BEL_PFE is not set
+# CONFIG_SENSORS_BPA_RS600 is not set
+# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set
+# CONFIG_SENSORS_FSP_3Y is not set
+CONFIG_SENSORS_IBM_CFFPS=m
+# CONFIG_SENSORS_DPS920AB is not set
+# CONFIG_SENSORS_INSPUR_IPSPS is not set
+CONFIG_SENSORS_IR35221=m
+# CONFIG_SENSORS_IR36021 is not set
+# CONFIG_SENSORS_IR38064 is not set
+# CONFIG_SENSORS_IRPS5401 is not set
+# CONFIG_SENSORS_ISL68137 is not set
+CONFIG_SENSORS_LM25066=m
+# CONFIG_SENSORS_LM25066_REGULATOR is not set
+# CONFIG_SENSORS_LT7182S is not set
+CONFIG_SENSORS_LTC2978=m
+CONFIG_SENSORS_LTC2978_REGULATOR=y
+CONFIG_SENSORS_LTC3815=m
+# CONFIG_SENSORS_MAX15301 is not set
+CONFIG_SENSORS_MAX16064=m
+# CONFIG_SENSORS_MAX16601 is not set
+# CONFIG_SENSORS_MAX20730 is not set
+CONFIG_SENSORS_MAX20751=m
+CONFIG_SENSORS_MAX31785=m
+CONFIG_SENSORS_MAX34440=m
+CONFIG_SENSORS_MAX8688=m
+# CONFIG_SENSORS_MP2888 is not set
+# CONFIG_SENSORS_MP2975 is not set
+# CONFIG_SENSORS_MP5023 is not set
+# CONFIG_SENSORS_MPQ7932 is not set
+# CONFIG_SENSORS_PIM4328 is not set
+# CONFIG_SENSORS_PLI1209BC is not set
+# CONFIG_SENSORS_PM6764TR is not set
+# CONFIG_SENSORS_PXE1610 is not set
+# CONFIG_SENSORS_Q54SJ108A2 is not set
+# CONFIG_SENSORS_STPDDC60 is not set
+# CONFIG_SENSORS_TDA38640 is not set
+CONFIG_SENSORS_TPS40422=m
+CONFIG_SENSORS_TPS53679=m
+# CONFIG_SENSORS_TPS546D24 is not set
+CONFIG_SENSORS_UCD9000=m
+CONFIG_SENSORS_UCD9200=m
+# CONFIG_SENSORS_XDPE152 is not set
+# CONFIG_SENSORS_XDPE122 is not set
+CONFIG_SENSORS_ZL6100=m
+# CONFIG_SENSORS_SBTSI is not set
+# CONFIG_SENSORS_SBRMI is not set
+CONFIG_SENSORS_SHT15=m
+CONFIG_SENSORS_SHT21=m
+CONFIG_SENSORS_SHT3x=m
+# CONFIG_SENSORS_SHT4x is not set
+CONFIG_SENSORS_SHTC1=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_DME1737=m
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+# CONFIG_SENSORS_EMC2305 is not set
+CONFIG_SENSORS_EMC6W201=m
+CONFIG_SENSORS_SMSC47M1=m
+CONFIG_SENSORS_SMSC47M192=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_SCH56XX_COMMON=m
+CONFIG_SENSORS_SCH5627=m
+CONFIG_SENSORS_SCH5636=m
+CONFIG_SENSORS_STTS751=m
+CONFIG_SENSORS_ADC128D818=m
+CONFIG_SENSORS_ADS7828=m
+CONFIG_SENSORS_AMC6821=m
+CONFIG_SENSORS_INA209=m
+CONFIG_SENSORS_INA2XX=m
+# CONFIG_SENSORS_INA238 is not set
+CONFIG_SENSORS_INA3221=m
+CONFIG_SENSORS_TC74=m
+CONFIG_SENSORS_THMC50=m
+CONFIG_SENSORS_TMP102=m
+CONFIG_SENSORS_TMP103=m
+CONFIG_SENSORS_TMP108=m
+CONFIG_SENSORS_TMP401=m
+CONFIG_SENSORS_TMP421=m
+# CONFIG_SENSORS_TMP464 is not set
+# CONFIG_SENSORS_TMP513 is not set
+CONFIG_SENSORS_VIA_CPUTEMP=m
+CONFIG_SENSORS_VIA686A=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83773G=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83795=m
+# CONFIG_SENSORS_W83795_FANCTRL is not set
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83L786NG=m
+CONFIG_SENSORS_W83627HF=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_SENSORS_XGENE=m
+
+#
+# ACPI drivers
+#
+CONFIG_SENSORS_ACPI_POWER=m
+CONFIG_SENSORS_ATK0110=m
+# CONFIG_SENSORS_ASUS_EC is not set
+CONFIG_THERMAL=y
+# CONFIG_THERMAL_NETLINK is not set
+# CONFIG_THERMAL_STATISTICS is not set
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_ACPI=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+# CONFIG_DEVFREQ_THERMAL is not set
+# CONFIG_THERMAL_EMULATION is not set
+
+#
+# Intel thermal drivers
+#
+CONFIG_INTEL_POWERCLAMP=m
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_INTEL_TCC=y
+CONFIG_X86_PKG_TEMP_THERMAL=m
+CONFIG_INTEL_SOC_DTS_IOSF_CORE=m
+CONFIG_INTEL_SOC_DTS_THERMAL=m
+
+#
+# ACPI INT340X thermal drivers
+#
+CONFIG_INT340X_THERMAL=m
+CONFIG_ACPI_THERMAL_REL=m
+CONFIG_PROC_THERMAL_MMIO_RAPL=m
+# end of ACPI INT340X thermal drivers
+
+CONFIG_INTEL_PCH_THERMAL=m
+# CONFIG_INTEL_TCC_COOLING is not set
+# CONFIG_INTEL_HFI_THERMAL is not set
+# end of Intel thermal drivers
+
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
+CONFIG_WATCHDOG_OPEN_TIMEOUT=0
+CONFIG_WATCHDOG_SYSFS=y
+# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
+
+#
+# Watchdog Pretimeout Governors
+#
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_MENF21BMC_WATCHDOG=m
+# CONFIG_WDAT_WDT is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_ZIIRAVE_WATCHDOG is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+CONFIG_ACQUIRE_WDT=m
+CONFIG_ADVANTECH_WDT=m
+# CONFIG_ADVANTECH_EC_WDT is not set
+CONFIG_ALIM1535_WDT=m
+CONFIG_ALIM7101_WDT=m
+# CONFIG_EBC_C384_WDT is not set
+# CONFIG_EXAR_WDT is not set
+CONFIG_F71808E_WDT=m
+CONFIG_SP5100_TCO=m
+CONFIG_SBC_FITPC2_WATCHDOG=m
+CONFIG_EUROTECH_WDT=m
+CONFIG_IB700_WDT=m
+CONFIG_IBMASR=m
+CONFIG_WAFER_WDT=m
+CONFIG_I6300ESB_WDT=m
+CONFIG_IE6XX_WDT=m
+CONFIG_ITCO_WDT=m
+CONFIG_ITCO_VENDOR_SUPPORT=y
+CONFIG_IT8712F_WDT=m
+CONFIG_IT87_WDT=m
+CONFIG_HP_WATCHDOG=m
+CONFIG_HPWDT_NMI_DECODING=y
+CONFIG_KEMPLD_WDT=m
+CONFIG_SC1200_WDT=m
+CONFIG_PC87413_WDT=m
+CONFIG_NV_TCO=m
+CONFIG_60XX_WDT=m
+CONFIG_CPU5_WDT=m
+CONFIG_SMSC_SCH311X_WDT=m
+CONFIG_SMSC37B787_WDT=m
+# CONFIG_TQMX86_WDT is not set
+CONFIG_VIA_WDT=m
+CONFIG_W83627HF_WDT=m
+CONFIG_W83877F_WDT=m
+CONFIG_W83977F_WDT=m
+CONFIG_MACHZ_WDT=m
+CONFIG_SBC_EPX_C3_WATCHDOG=m
+# CONFIG_INTEL_MEI_WDT is not set
+# CONFIG_NI903X_WDT is not set
+# CONFIG_NIC7018_WDT is not set
+# CONFIG_MEN_A21_WDT is not set
+CONFIG_XEN_WDT=m
+
+#
+# PCI-based Watchdog Cards
+#
+CONFIG_PCIPCWATCHDOG=m
+CONFIG_WDTPCI=m
+
+#
+# USB-based Watchdog Cards
+#
+CONFIG_USBPCWATCHDOG=m
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB=m
+CONFIG_SSB_SPROM=y
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_B43_PCI_BRIDGE=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+CONFIG_SSB_SDIOHOST=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_DRIVER_PCICORE=y
+# CONFIG_SSB_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+CONFIG_BCMA=m
+CONFIG_BCMA_BLOCKIO=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+CONFIG_BCMA_HOST_PCI=y
+# CONFIG_BCMA_HOST_SOC is not set
+CONFIG_BCMA_DRIVER_PCI=y
+# CONFIG_BCMA_DRIVER_GMAC_CMN is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+# CONFIG_BCMA_DEBUG is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_SMPRO is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_BD9571MWV is not set
+CONFIG_MFD_AXP20X=m
+CONFIG_MFD_AXP20X_I2C=m
+# CONFIG_MFD_CS42L43_I2C is not set
+# CONFIG_MFD_MADERA is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MP2629 is not set
+# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
+CONFIG_LPC_ICH=m
+CONFIG_LPC_SCH=m
+# CONFIG_INTEL_SOC_PMIC is not set
+CONFIG_INTEL_SOC_PMIC_CHTWC=y
+# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set
+CONFIG_MFD_INTEL_LPSS=m
+CONFIG_MFD_INTEL_LPSS_ACPI=m
+CONFIG_MFD_INTEL_LPSS_PCI=m
+# CONFIG_MFD_INTEL_PMC_BXT is not set
+# CONFIG_MFD_IQS62X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+CONFIG_MFD_KEMPLD=m
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77541 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MT6360 is not set
+# CONFIG_MFD_MT6370 is not set
+# CONFIG_MFD_MT6397 is not set
+CONFIG_MFD_MENF21BMC=m
+CONFIG_MFD_VIPERBOARD=m
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_SY7636A is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RT4831 is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RT5120 is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SKY81452 is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_TI_LMU is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65086 is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TI_LP873X is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS6594_I2C is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TQMX86 is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_ATC260X_I2C is not set
+# CONFIG_RAVE_SP_CORE is not set
+# end of Multifunction device drivers
+
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_REGULATOR_88PG86X=m
+CONFIG_REGULATOR_ACT8865=m
+CONFIG_REGULATOR_AD5398=m
+# CONFIG_REGULATOR_AW37503 is not set
+CONFIG_REGULATOR_AXP20X=m
+CONFIG_REGULATOR_DA9210=m
+CONFIG_REGULATOR_DA9211=m
+CONFIG_REGULATOR_FAN53555=m
+CONFIG_REGULATOR_GPIO=m
+CONFIG_REGULATOR_ISL9305=m
+CONFIG_REGULATOR_ISL6271A=m
+CONFIG_REGULATOR_LP3971=m
+CONFIG_REGULATOR_LP3972=m
+CONFIG_REGULATOR_LP872X=m
+CONFIG_REGULATOR_LP8755=m
+CONFIG_REGULATOR_LTC3589=m
+CONFIG_REGULATOR_LTC3676=m
+CONFIG_REGULATOR_MAX1586=m
+# CONFIG_REGULATOR_MAX77857 is not set
+CONFIG_REGULATOR_MAX8649=m
+CONFIG_REGULATOR_MAX8660=m
+# CONFIG_REGULATOR_MAX8893 is not set
+CONFIG_REGULATOR_MAX8952=m
+# CONFIG_REGULATOR_MAX20086 is not set
+# CONFIG_REGULATOR_MAX20411 is not set
+# CONFIG_REGULATOR_MAX77826 is not set
+# CONFIG_REGULATOR_MP8859 is not set
+CONFIG_REGULATOR_MT6311=m
+# CONFIG_REGULATOR_PCA9450 is not set
+CONFIG_REGULATOR_PV88060=m
+CONFIG_REGULATOR_PV88080=m
+CONFIG_REGULATOR_PV88090=m
+# CONFIG_REGULATOR_RAA215300 is not set
+# CONFIG_REGULATOR_RT4801 is not set
+# CONFIG_REGULATOR_RT4803 is not set
+# CONFIG_REGULATOR_RT5190A is not set
+# CONFIG_REGULATOR_RT5739 is not set
+# CONFIG_REGULATOR_RT5759 is not set
+# CONFIG_REGULATOR_RT6160 is not set
+# CONFIG_REGULATOR_RT6190 is not set
+# CONFIG_REGULATOR_RT6245 is not set
+# CONFIG_REGULATOR_RTQ2134 is not set
+# CONFIG_REGULATOR_RTMV20 is not set
+# CONFIG_REGULATOR_RTQ6752 is not set
+# CONFIG_REGULATOR_RTQ2208 is not set
+# CONFIG_REGULATOR_SLG51000 is not set
+CONFIG_REGULATOR_TPS51632=m
+CONFIG_REGULATOR_TPS62360=m
+CONFIG_REGULATOR_TPS65023=m
+CONFIG_REGULATOR_TPS6507X=m
+CONFIG_REGULATOR_TPS65132=m
+# CONFIG_RC_CORE is not set
+
+#
+# CEC support
+#
+# CONFIG_MEDIA_CEC_SUPPORT is not set
+# end of CEC support
+
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_APERTURE_HELPERS=y
+CONFIG_SCREEN_INFO=y
+CONFIG_VIDEO_CMDLINE=y
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_PANEL is not set
+# CONFIG_AGP is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_DEBUG_MODESET_LOCK is not set
+CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+CONFIG_FB_VESA=y
+CONFIG_FB_EFI=y
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_XEN_FBDEV_FRONTEND is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_HYPERV is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SM712 is not set
+CONFIG_FB_CORE=y
+CONFIG_FB_NOTIFY=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_DEVICE=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_IOMEM_FOPS=y
+CONFIG_FB_IOMEM_HELPERS=y
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# end of Frame buffer Devices
+
+#
+# Backlight & LCD device support
+#
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+# end of Backlight & LCD device support
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
+# end of Console display driver support
+
+# CONFIG_LOGO is not set
+# end of Graphics support
+
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=m
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=m
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACCUTOUCH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_ASUS is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_BIGBEN_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_COUGAR is not set
+# CONFIG_HID_MACALLY is not set
+# CONFIG_HID_CMEDIA is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CREATIVE_SB0540 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELAN is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EVISION is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_FT260 is not set
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_GLORIOUS is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_GOOGLE_STADIA_FF is not set
+# CONFIG_HID_VIVALDI is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_VIEWSONIC is not set
+# CONFIG_HID_VRC2 is not set
+# CONFIG_HID_XIAOMI is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_ITE is not set
+# CONFIG_HID_JABRA is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LED is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LETSKETCH is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MALTRON is not set
+# CONFIG_HID_MAYFLASH is not set
+# CONFIG_HID_MEGAWORLD_FF is not set
+# CONFIG_HID_REDRAGON is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NINTENDO is not set
+# CONFIG_HID_NTI is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PXRC is not set
+# CONFIG_HID_RAZER is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_RETRODE is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SEMITEK is not set
+# CONFIG_HID_SIGMAMICRO is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEAM is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_HYPERV_MOUSE is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TOPRE is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_UDRAW_PS3 is not set
+# CONFIG_HID_U2FZERO is not set
+# CONFIG_HID_UNIVERSAL_PIDFF is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_ALPS is not set
+# CONFIG_HID_MCP2200 is not set
+# CONFIG_HID_MCP2221 is not set
+# end of Special HID drivers
+
+#
+# HID-BPF support
+#
+# end of HID-BPF support
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=m
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# end of USB HID Boot Protocol drivers
+# end of USB HID support
+
+CONFIG_I2C_HID=m
+# CONFIG_I2C_HID_ACPI is not set
+# CONFIG_I2C_HID_OF is not set
+
+#
+# Intel ISH HID support
+#
+# CONFIG_INTEL_ISH_HID is not set
+# end of Intel ISH HID support
+
+#
+# AMD SFH HID Support
+#
+# CONFIG_AMD_SFH_HID is not set
+# end of AMD SFH HID Support
+
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_ULPI_BUS is not set
+# CONFIG_USB_CONN_GPIO is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+CONFIG_USB_PCI=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_FEW_INIT_RETRIES is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_PRODUCTLIST is not set
+# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
+# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
+CONFIG_USB_AUTOSUSPEND_DELAY=2
+# CONFIG_USB_MON is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_XHCI_HCD=m
+# CONFIG_USB_XHCI_DBGCAP is not set
+CONFIG_USB_XHCI_PCI=m
+# CONFIG_USB_XHCI_PCI_RENESAS is not set
+# CONFIG_USB_XHCI_PLATFORM is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_PCI=m
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PCI=m
+# CONFIG_USB_OHCI_HCD_SSB is not set
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_SL811_HCD=m
+# CONFIG_USB_SL811_HCD_ISO is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_BCMA is not set
+# CONFIG_USB_HCD_SSB is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_XEN_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_UAS is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+
+#
+# USB dual-mode controller drivers
+#
+# CONFIG_USB_CDNS_SUPPORT is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_ISP1760 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_F8153X=m
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+CONFIG_USB_SERIAL_IUU=m
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_METRO is not set
+CONFIG_USB_SERIAL_MOS7720=m
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MXUPORT=m
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_SYMBOL is not set
+CONFIG_USB_SERIAL_TI=m
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_OPTION=m
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+CONFIG_USB_SERIAL_UPD78F0730=m
+# CONFIG_USB_SERIAL_XR is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_APPLE_MFI_FASTCHARGE is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_EZUSB_FX2=m
+# CONFIG_USB_HUB_USB251XB is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSIC_USB4604 is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_CHAOSKEY is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ISP1301 is not set
+# end of USB Physical Layer drivers
+
+# CONFIG_USB_GADGET is not set
+# CONFIG_TYPEC is not set
+# CONFIG_USB_ROLE_SWITCH is not set
+CONFIG_MMC=m
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_MINORS=256
+CONFIG_SDIO_UART=m
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_SDHCI=m
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_PCI=m
+CONFIG_MMC_RICOH_MMC=y
+CONFIG_MMC_SDHCI_ACPI=m
+CONFIG_MMC_SDHCI_PLTFM=m
+CONFIG_MMC_SDHCI_F_SDH30=m
+CONFIG_MMC_WBSD=m
+CONFIG_MMC_TIFM_SD=m
+CONFIG_MMC_CB710=m
+CONFIG_MMC_VIA_SDMMC=m
+CONFIG_MMC_VUB300=m
+CONFIG_MMC_USHC=m
+CONFIG_MMC_USDHI6ROL0=m
+CONFIG_MMC_REALTEK_PCI=m
+CONFIG_MMC_REALTEK_USB=m
+CONFIG_MMC_CQHCI=m
+# CONFIG_MMC_HSQ is not set
+# CONFIG_MMC_TOSHIBA_PCI is not set
+CONFIG_MMC_MTK=m
+CONFIG_MMC_SDHCI_XENON=m
+CONFIG_SCSI_UFSHCD=m
+# CONFIG_SCSI_UFS_BSG is not set
+# CONFIG_SCSI_UFS_HWMON is not set
+CONFIG_SCSI_UFSHCD_PCI=m
+# CONFIG_SCSI_UFS_DWC_TC_PCI is not set
+# CONFIG_SCSI_UFSHCD_PLATFORM is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_CLASS_FLASH=m
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_APU is not set
+# CONFIG_LEDS_AW200XX is not set
+# CONFIG_LEDS_CHT_WCOVE is not set
+CONFIG_LEDS_LM3530=m
+# CONFIG_LEDS_LM3532 is not set
+CONFIG_LEDS_LM3642=m
+CONFIG_LEDS_PCA9532=m
+# CONFIG_LEDS_PCA9532_GPIO is not set
+CONFIG_LEDS_GPIO=m
+CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_LP3952=m
+# CONFIG_LEDS_LP50XX is not set
+CONFIG_LEDS_PCA955X=m
+# CONFIG_LEDS_PCA955X_GPIO is not set
+CONFIG_LEDS_PCA963X=m
+# CONFIG_LEDS_PCA995X is not set
+CONFIG_LEDS_REGULATOR=m
+# CONFIG_LEDS_BD2606MVV is not set
+CONFIG_LEDS_BD2802=m
+CONFIG_LEDS_INTEL_SS4200=m
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TCA6507=m
+CONFIG_LEDS_TLC591XX=m
+CONFIG_LEDS_LM355x=m
+CONFIG_LEDS_MENF21BMC=m
+# CONFIG_LEDS_IS31FL319X is not set
+
+#
+# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
+#
+CONFIG_LEDS_BLINKM=m
+CONFIG_LEDS_MLXCPLD=m
+CONFIG_LEDS_MLXREG=m
+# CONFIG_LEDS_USER is not set
+CONFIG_LEDS_NIC78BX=m
+
+#
+# Flash and Torch LED drivers
+#
+CONFIG_LEDS_AS3645A=m
+CONFIG_LEDS_LM3601X=m
+# CONFIG_LEDS_RT8515 is not set
+# CONFIG_LEDS_SGM3140 is not set
+
+#
+# RGB LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_ONESHOT=m
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_ACTIVITY=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+CONFIG_LEDS_TRIGGER_TRANSIENT=m
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_LEDS_TRIGGER_NETDEV=m
+# CONFIG_LEDS_TRIGGER_PATTERN is not set
+# CONFIG_LEDS_TRIGGER_AUDIO is not set
+# CONFIG_LEDS_TRIGGER_TTY is not set
+
+#
+# Simple LED drivers
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_INFINIBAND=m
+# CONFIG_INFINIBAND_USER_MAD is not set
+CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_USER_MEM=y
+CONFIG_INFINIBAND_ON_DEMAND_PAGING=y
+CONFIG_INFINIBAND_ADDR_TRANS=y
+CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y
+CONFIG_INFINIBAND_VIRT_DMA=y
+# CONFIG_INFINIBAND_BNXT_RE is not set
+# CONFIG_INFINIBAND_CXGB4 is not set
+# CONFIG_INFINIBAND_EFA is not set
+# CONFIG_INFINIBAND_ERDMA is not set
+# CONFIG_INFINIBAND_IRDMA is not set
+CONFIG_MLX4_INFINIBAND=m
+CONFIG_MLX5_INFINIBAND=m
+# CONFIG_INFINIBAND_MTHCA is not set
+# CONFIG_INFINIBAND_OCRDMA is not set
+# CONFIG_INFINIBAND_QEDR is not set
+# CONFIG_INFINIBAND_USNIC is not set
+# CONFIG_INFINIBAND_VMWARE_PVRDMA is not set
+# CONFIG_INFINIBAND_RDMAVT is not set
+# CONFIG_RDMA_RXE is not set
+# CONFIG_RDMA_SIW is not set
+# CONFIG_INFINIBAND_IPOIB is not set
+# CONFIG_INFINIBAND_SRP is not set
+# CONFIG_INFINIBAND_ISER is not set
+# CONFIG_INFINIBAND_RTRS_CLIENT is not set
+# CONFIG_INFINIBAND_RTRS_SERVER is not set
+# CONFIG_INFINIBAND_OPA_VNIC is not set
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EDAC=y
+CONFIG_EDAC_LEGACY_SYSFS=y
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_DECODE_MCE=m
+# CONFIG_EDAC_GHES is not set
+CONFIG_EDAC_AMD64=m
+CONFIG_EDAC_E752X=m
+CONFIG_EDAC_I82975X=m
+CONFIG_EDAC_I3000=m
+CONFIG_EDAC_I3200=m
+CONFIG_EDAC_IE31200=m
+CONFIG_EDAC_X38=m
+CONFIG_EDAC_I5400=m
+CONFIG_EDAC_I7CORE=m
+CONFIG_EDAC_I5100=m
+CONFIG_EDAC_I7300=m
+CONFIG_EDAC_SBRIDGE=m
+CONFIG_EDAC_SKX=m
+# CONFIG_EDAC_I10NM is not set
+CONFIG_EDAC_PND2=m
+# CONFIG_EDAC_IGEN6 is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_MC146818_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+CONFIG_RTC_NVMEM=y
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABEOZ9 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF85363 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8010 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3028 is not set
+# CONFIG_RTC_DRV_RV3032 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+# CONFIG_RTC_DRV_SD3078 is not set
+
+#
+# SPI RTC drivers
+#
+CONFIG_RTC_I2C_AND_SPI=y
+
+#
+# SPI and I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RX6110 is not set
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_FTRTC010 is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_GOLDFISH is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DMA_ACPI=y
+# CONFIG_ALTERA_MSGDMA is not set
+CONFIG_INTEL_IDMA64=y
+CONFIG_INTEL_IDXD_BUS=y
+CONFIG_INTEL_IDXD=y
+# CONFIG_INTEL_IDXD_COMPAT is not set
+# CONFIG_INTEL_IDXD_SVM is not set
+# CONFIG_INTEL_IDXD_PERFMON is not set
+CONFIG_INTEL_IOATDMA=y
+# CONFIG_PLX_DMA is not set
+# CONFIG_XILINX_DMA is not set
+# CONFIG_XILINX_XDMA is not set
+# CONFIG_AMD_PTDMA is not set
+# CONFIG_QCOM_HIDMA_MGMT is not set
+# CONFIG_QCOM_HIDMA is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_DMAC_PCI is not set
+# CONFIG_DW_EDMA is not set
+CONFIG_HSU_DMA=y
+# CONFIG_SF_PDMA is not set
+# CONFIG_INTEL_LDMA is not set
+
+#
+# DMA Clients
+#
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+CONFIG_DMA_ENGINE_RAID=y
+
+#
+# DMABUF options
+#
+CONFIG_SYNC_FILE=y
+# CONFIG_SW_SYNC is not set
+# CONFIG_UDMABUF is not set
+# CONFIG_DMABUF_MOVE_NOTIFY is not set
+# CONFIG_DMABUF_DEBUG is not set
+# CONFIG_DMABUF_SELFTESTS is not set
+# CONFIG_DMABUF_HEAPS is not set
+# CONFIG_DMABUF_SYSFS_STATS is not set
+# end of DMABUF options
+
+CONFIG_DCA=y
+CONFIG_UIO=m
+# CONFIG_UIO_CIF is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_DMEM_GENIRQ is not set
+# CONFIG_UIO_AEC is not set
+# CONFIG_UIO_SERCOS3 is not set
+CONFIG_UIO_PCI_GENERIC=m
+# CONFIG_UIO_NETX is not set
+# CONFIG_UIO_PRUSS is not set
+# CONFIG_UIO_MF624 is not set
+CONFIG_UIO_HV_GENERIC=m
+CONFIG_VFIO=m
+CONFIG_VFIO_GROUP=y
+CONFIG_VFIO_CONTAINER=y
+CONFIG_VFIO_IOMMU_TYPE1=m
+CONFIG_VFIO_NOIOMMU=y
+CONFIG_VFIO_VIRQFD=y
+
+#
+# VFIO support for PCI devices
+#
+CONFIG_VFIO_PCI_CORE=m
+CONFIG_VFIO_PCI_MMAP=y
+CONFIG_VFIO_PCI_INTX=y
+CONFIG_VFIO_PCI=m
+CONFIG_VFIO_PCI_IGD=y
+CONFIG_MLX5_VFIO_PCI=m
+# end of VFIO support for PCI devices
+
+CONFIG_IRQ_BYPASS_MANAGER=m
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRTIO_ANCHOR=y
+CONFIG_VIRTIO=m
+CONFIG_VIRTIO_PCI_LIB=m
+CONFIG_VIRTIO_PCI_LIB_LEGACY=m
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_PCI=m
+CONFIG_VIRTIO_PCI_LEGACY=y
+CONFIG_VIRTIO_VDPA=m
+# CONFIG_VIRTIO_PMEM is not set
+CONFIG_VIRTIO_BALLOON=m
+CONFIG_VIRTIO_INPUT=m
+CONFIG_VIRTIO_MMIO=m
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VDPA=m
+# CONFIG_VDPA_USER is not set
+# CONFIG_IFCVF is not set
+# CONFIG_MLX5_VDPA_NET is not set
+# CONFIG_MLX5_VDPA_STEERING_DEBUG is not set
+# CONFIG_VP_VDPA is not set
+# CONFIG_ALIBABA_ENI_VDPA is not set
+# CONFIG_SNET_VDPA is not set
+CONFIG_VHOST_IOTLB=m
+CONFIG_VHOST_TASK=y
+CONFIG_VHOST=m
+CONFIG_VHOST_MENU=y
+CONFIG_VHOST_NET=m
+CONFIG_VHOST_VSOCK=m
+CONFIG_VHOST_VDPA=m
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_HYPERV=m
+# CONFIG_HYPERV_VTL_MODE is not set
+CONFIG_HYPERV_TIMER=y
+CONFIG_HYPERV_UTILS=m
+CONFIG_HYPERV_BALLOON=m
+# end of Microsoft Hyper-V guest support
+
+#
+# Xen driver support
+#
+CONFIG_XEN_BALLOON=y
+CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
+CONFIG_XEN_DEV_EVTCHN=m
+CONFIG_XEN_BACKEND=y
+CONFIG_XENFS=m
+CONFIG_XEN_COMPAT_XENFS=y
+CONFIG_XEN_SYS_HYPERVISOR=y
+CONFIG_XEN_XENBUS_FRONTEND=y
+CONFIG_XEN_GNTDEV=m
+CONFIG_XEN_GRANT_DEV_ALLOC=m
+# CONFIG_XEN_GRANT_DMA_ALLOC is not set
+CONFIG_SWIOTLB_XEN=y
+CONFIG_XEN_PCI_STUB=y
+CONFIG_XEN_PCIDEV_BACKEND=m
+# CONFIG_XEN_PVCALLS_FRONTEND is not set
+# CONFIG_XEN_PVCALLS_BACKEND is not set
+CONFIG_XEN_PRIVCMD=m
+CONFIG_XEN_ACPI_PROCESSOR=m
+CONFIG_XEN_MCE_LOG=y
+CONFIG_XEN_HAVE_PVMMU=y
+CONFIG_XEN_EFI=y
+CONFIG_XEN_AUTO_XLATE=y
+CONFIG_XEN_ACPI=y
+CONFIG_XEN_SYMS=y
+CONFIG_XEN_HAVE_VPMU=y
+# CONFIG_XEN_VIRTIO is not set
+# end of Xen driver support
+
+# CONFIG_GREYBUS is not set
+# CONFIG_COMEDI is not set
+# CONFIG_STAGING is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_MELLANOX_PLATFORM is not set
+CONFIG_SURFACE_PLATFORMS=y
+# CONFIG_SURFACE_3_POWER_OPREGION is not set
+# CONFIG_SURFACE_GPE is not set
+# CONFIG_SURFACE_HOTPLUG is not set
+# CONFIG_SURFACE_PRO3_BUTTON is not set
+# CONFIG_SURFACE_AGGREGATOR is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+# CONFIG_ACPI_WMI is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACER_WIRELESS is not set
+# CONFIG_AMD_PMF is not set
+# CONFIG_AMD_PMC is not set
+# CONFIG_AMD_HSMP is not set
+# CONFIG_ADV_SWBUTTON is not set
+# CONFIG_ASUS_WIRELESS is not set
+# CONFIG_ASUS_TF103C_DOCK is not set
+# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_GPD_POCKET_FAN is not set
+# CONFIG_X86_PLATFORM_DRIVERS_HP is not set
+# CONFIG_WIRELESS_HOTKEY is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_INTEL_ATOMISP2_LED is not set
+# CONFIG_INTEL_ATOMISP2_PM is not set
+# CONFIG_INTEL_IFS is not set
+# CONFIG_INTEL_SAR_INT1092 is not set
+# CONFIG_INTEL_SKL_INT3472 is not set
+# CONFIG_INTEL_PMC_CORE is not set
+
+#
+# Intel Speed Select Technology interface support
+#
+# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set
+# end of Intel Speed Select Technology interface support
+
+#
+# Intel Uncore Frequency Control
+#
+# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set
+# end of Intel Uncore Frequency Control
+
+# CONFIG_INTEL_HID_EVENT is not set
+# CONFIG_INTEL_VBTN is not set
+# CONFIG_INTEL_INT0002_VGPIO is not set
+# CONFIG_INTEL_PUNIT_IPC is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_INTEL_TURBO_MAX_3 is not set
+# CONFIG_INTEL_VSEC is not set
+# CONFIG_PCENGINES_APU2 is not set
+# CONFIG_BARCO_P50_GPIO is not set
+# CONFIG_SAMSUNG_Q10 is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_ACPI_CMPC is not set
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_MLX_PLATFORM is not set
+# CONFIG_INTEL_IPS is not set
+# CONFIG_INTEL_SCU_PCI is not set
+# CONFIG_INTEL_SCU_PLATFORM is not set
+# CONFIG_SIEMENS_SIMATIC_IPC is not set
+# CONFIG_WINMATE_FM07_KEYS is not set
+# CONFIG_SEL3350_PLATFORM is not set
+CONFIG_P2SB=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+# CONFIG_COMMON_CLK_MAX9485 is not set
+# CONFIG_COMMON_CLK_SI5341 is not set
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI544 is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_CS2000_CP is not set
+# CONFIG_XILINX_VCU is not set
+# CONFIG_HWSPINLOCK is not set
+
+#
+# Clock Source drivers
+#
+CONFIG_CLKEVT_I8253=y
+CONFIG_I8253_LOCK=y
+CONFIG_CLKBLD_I8253=y
+# end of Clock Source drivers
+
+CONFIG_MAILBOX=y
+CONFIG_PCC=y
+# CONFIG_ALTERA_MBOX is not set
+CONFIG_IOMMU_IOVA=y
+CONFIG_IOMMU_API=y
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Generic IOMMU Pagetable Support
+#
+CONFIG_IOMMU_IO_PGTABLE=y
+# end of Generic IOMMU Pagetable Support
+
+# CONFIG_IOMMU_DEBUGFS is not set
+# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
+# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
+CONFIG_IOMMU_DMA=y
+CONFIG_IOMMU_SVA=y
+CONFIG_AMD_IOMMU=y
+CONFIG_AMD_IOMMU_V2=y
+CONFIG_DMAR_TABLE=y
+CONFIG_INTEL_IOMMU=y
+CONFIG_INTEL_IOMMU_SVM=y
+# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set
+CONFIG_INTEL_IOMMU_FLOPPY_WA=y
+# CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON is not set
+CONFIG_INTEL_IOMMU_PERF_EVENTS=y
+# CONFIG_IOMMUFD is not set
+CONFIG_IRQ_REMAP=y
+CONFIG_HYPERV_IOMMU=y
+# CONFIG_VIRTIO_IOMMU is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_REMOTEPROC is not set
+# end of Remoteproc drivers
+
+#
+# Rpmsg drivers
+#
+# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
+# CONFIG_RPMSG_VIRTIO is not set
+# end of Rpmsg drivers
+
+# CONFIG_SOUNDWIRE is not set
+
+#
+# SOC (System On Chip) specific Drivers
+#
+
+#
+# Amlogic SoC drivers
+#
+# end of Amlogic SoC drivers
+
+#
+# Broadcom SoC drivers
+#
+# end of Broadcom SoC drivers
+
+#
+# NXP/Freescale QorIQ SoC drivers
+#
+# end of NXP/Freescale QorIQ SoC drivers
+
+#
+# fujitsu SoC drivers
+#
+# end of fujitsu SoC drivers
+
+#
+# i.MX SoC drivers
+#
+# end of i.MX SoC drivers
+
+#
+# Enable LiteX SoC Builder specific drivers
+#
+# end of Enable LiteX SoC Builder specific drivers
+
+# CONFIG_WPCM450_SOC is not set
+
+#
+# Qualcomm SoC drivers
+#
+# end of Qualcomm SoC drivers
+
+# CONFIG_SOC_TI is not set
+
+#
+# Xilinx SoC drivers
+#
+# end of Xilinx SoC drivers
+# end of SOC (System On Chip) specific Drivers
+
+CONFIG_PM_DEVFREQ=y
+
+#
+# DEVFREQ Governors
+#
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m
+# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
+# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
+# CONFIG_DEVFREQ_GOV_USERSPACE is not set
+# CONFIG_DEVFREQ_GOV_PASSIVE is not set
+
+#
+# DEVFREQ Drivers
+#
+# CONFIG_PM_DEVFREQ_EVENT is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+# CONFIG_IIO is not set
+# CONFIG_NTB is not set
+# CONFIG_PWM is not set
+
+#
+# IRQ chip support
+#
+# end of IRQ chip support
+
+# CONFIG_IPACK_BUS is not set
+CONFIG_RESET_CONTROLLER=y
+# CONFIG_RESET_SIMPLE is not set
+# CONFIG_RESET_TI_SYSCON is not set
+# CONFIG_RESET_TI_TPS380X is not set
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+# CONFIG_USB_LGM_PHY is not set
+# CONFIG_PHY_CAN_TRANSCEIVER is not set
+
+#
+# PHY drivers for Broadcom platforms
+#
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# end of PHY drivers for Broadcom platforms
+
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_PHY_INTEL_LGM_EMMC is not set
+# end of PHY Subsystem
+
+CONFIG_POWERCAP=y
+CONFIG_INTEL_RAPL_CORE=m
+# CONFIG_INTEL_RAPL is not set
+CONFIG_IDLE_INJECT=y
+# CONFIG_MCB is not set
+
+#
+# Performance monitor support
+#
+# end of Performance monitor support
+
+CONFIG_RAS=y
+# CONFIG_RAS_CEC is not set
+CONFIG_USB4=m
+# CONFIG_USB4_DEBUGFS_WRITE is not set
+# CONFIG_USB4_DMA_TEST is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID_BINDER_IPC is not set
+# end of Android
+
+CONFIG_LIBNVDIMM=m
+CONFIG_BLK_DEV_PMEM=m
+CONFIG_ND_CLAIM=y
+CONFIG_ND_BTT=m
+CONFIG_BTT=y
+CONFIG_DAX=y
+# CONFIG_DEV_DAX is not set
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+
+#
+# Layout Types
+#
+# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
+# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
+# end of Layout Types
+
+# CONFIG_NVMEM_RMEM is not set
+
+#
+# HW tracing support
+#
+# CONFIG_STM is not set
+# CONFIG_INTEL_TH is not set
+# end of HW tracing support
+
+# CONFIG_FPGA is not set
+# CONFIG_TEE is not set
+CONFIG_PM_OPP=y
+# CONFIG_SIOX is not set
+# CONFIG_SLIMBUS is not set
+# CONFIG_INTERCONNECT is not set
+# CONFIG_COUNTER is not set
+# CONFIG_MOST is not set
+# CONFIG_PECI is not set
+# CONFIG_HTE is not set
+# end of Device Drivers
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_VALIDATE_FS_PARSER is not set
+CONFIG_FS_IOMAP=y
+CONFIG_BUFFER_HEAD=y
+CONFIG_LEGACY_DIRECT_IO=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=m
+CONFIG_EXT4_USE_FOR_EXT2=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=m
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_F2FS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FS_ENCRYPTION is not set
+# CONFIG_FS_VERITY is not set
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_CUSE=m
+CONFIG_VIRTIO_FS=m
+CONFIG_OVERLAY_FS=m
+# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
+CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
+# CONFIG_OVERLAY_FS_INDEX is not set
+# CONFIG_OVERLAY_FS_XINO_AUTO is not set
+# CONFIG_OVERLAY_FS_METACOPY is not set
+# CONFIG_OVERLAY_FS_DEBUG is not set
+
+#
+# Caches
+#
+CONFIG_NETFS_SUPPORT=m
+CONFIG_NETFS_STATS=y
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_CACHEFILES is not set
+# end of Caches
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+# end of CD-ROM/DVD Filesystems
+
+#
+# DOS/FAT/EXFAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_FAT_DEFAULT_UTF8=y
+CONFIG_EXFAT_FS=m
+CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8"
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS3_FS is not set
+# end of DOS/FAT/EXFAT/NT Filesystems
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_CHILDREN=y
+CONFIG_PROC_PID_ARCH_STATUS=y
+CONFIG_KERNFS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TMPFS_INODE64 is not set
+# CONFIG_TMPFS_QUOTA is not set
+CONFIG_HUGETLBFS=y
+# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
+CONFIG_HUGETLB_PAGE=y
+CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
+CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_EFIVAR_FS=m
+# end of Pseudo filesystems
+
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ORANGEFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_FILE_CACHE=y
+# CONFIG_SQUASHFS_FILE_DIRECT is not set
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
+CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
+# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_LZ4=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_ZSTD=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_PSTORE=y
+CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
+CONFIG_PSTORE_COMPRESS=y
+# CONFIG_PSTORE_CONSOLE is not set
+# CONFIG_PSTORE_PMSG is not set
+# CONFIG_PSTORE_RAM is not set
+# CONFIG_PSTORE_BLK is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_EROFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+# CONFIG_UNICODE is not set
+# end of File systems
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_REQUEST_CACHE is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_TRUSTED_KEYS is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_KEY_DH_OPERATIONS is not set
+CONFIG_SECURITY_DMESG_RESTRICT=y
+CONFIG_PROC_MEM_ALWAYS_FORCE=y
+# CONFIG_PROC_MEM_FORCE_PTRACE is not set
+# CONFIG_PROC_MEM_NO_FORCE is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_INFINIBAND is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_INTEL_TXT is not set
+# CONFIG_HARDENED_USERCOPY is not set
+CONFIG_FORTIFY_SOURCE=y
+# CONFIG_STATIC_USERMODEHELPER is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_SECURITY_LOADPIN is not set
+# CONFIG_SECURITY_YAMA is not set
+# CONFIG_SECURITY_SAFESETID is not set
+CONFIG_SECURITY_LOCKDOWN_LSM=y
+CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
+CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y
+# CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY is not set
+# CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY is not set
+# CONFIG_SECURITY_LANDLOCK is not set
+# CONFIG_INTEGRITY is not set
+# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
+
+#
+# Kernel hardening options
+#
+
+#
+# Memory initialization
+#
+CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
+CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
+CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
+CONFIG_INIT_STACK_NONE=y
+# CONFIG_INIT_STACK_ALL_PATTERN is not set
+# CONFIG_INIT_STACK_ALL_ZERO is not set
+# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
+# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
+CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
+# CONFIG_ZERO_CALL_USED_REGS is not set
+# end of Memory initialization
+
+#
+# Hardening of kernel data structures
+#
+CONFIG_LIST_HARDENED=y
+CONFIG_BUG_ON_DATA_CORRUPTION=y
+# end of Hardening of kernel data structures
+
+CONFIG_RANDSTRUCT_NONE=y
+# end of Kernel hardening options
+# end of Security options
+
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_ASYNC_PQ=y
+CONFIG_ASYNC_RAID6_RECOV=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_SIG=y
+CONFIG_CRYPTO_SIG2=y
+CONFIG_CRYPTO_SKCIPHER=y
+CONFIG_CRYPTO_SKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=m
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_AKCIPHER=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_KPP=m
+CONFIG_CRYPTO_ACOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_USER=m
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_SIMD=m
+CONFIG_CRYPTO_ENGINE=m
+# end of Crypto core or helper
+
+#
+# Public-key cryptography
+#
+CONFIG_CRYPTO_RSA=y
+CONFIG_CRYPTO_DH=m
+# CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set
+CONFIG_CRYPTO_ECC=m
+CONFIG_CRYPTO_ECDH=m
+CONFIG_CRYPTO_ECDSA=m
+CONFIG_CRYPTO_ECRDSA=m
+# CONFIG_CRYPTO_SM2 is not set
+# CONFIG_CRYPTO_CURVE25519 is not set
+# end of Public-key cryptography
+
+#
+# Block ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_AES_TI=m
+CONFIG_CRYPTO_ANUBIS=m
+# CONFIG_CRYPTO_ARIA is not set
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+# CONFIG_CRYPTO_SM4_GENERIC is not set
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+# end of Block ciphers
+
+#
+# Length-preserving ciphers and modes
+#
+CONFIG_CRYPTO_ADIANTUM=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_CHACHA20=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CFB=m
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_HCTR2 is not set
+CONFIG_CRYPTO_KEYWRAP=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_OFB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_NHPOLY1305=m
+# end of Length-preserving ciphers and modes
+
+#
+# AEAD (authenticated encryption with associated data) ciphers
+#
+CONFIG_CRYPTO_AEGIS128=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_GENIV=m
+CONFIG_CRYPTO_SEQIV=m
+CONFIG_CRYPTO_ECHAINIV=m
+CONFIG_CRYPTO_ESSIV=y
+# end of AEAD (authenticated encryption with associated data) ciphers
+
+#
+# Hashes, digests, and MACs
+#
+# CONFIG_CRYPTO_BLAKE2B is not set
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_GHASH=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_POLY1305=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_SHA3=m
+# CONFIG_CRYPTO_SM3_GENERIC is not set
+CONFIG_CRYPTO_STREEBOG=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_XXHASH=m
+# end of Hashes, digests, and MACs
+
+#
+# CRCs (cyclic redundancy checks)
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_CRC32=m
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_CRC64_ROCKSOFT=y
+# end of CRCs (cyclic redundancy checks)
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_842=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
+CONFIG_CRYPTO_ZSTD=m
+# end of Compression
+
+#
+# Random number generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_DRBG_MENU=m
+CONFIG_CRYPTO_DRBG_HMAC=y
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+CONFIG_CRYPTO_DRBG=m
+CONFIG_CRYPTO_JITTERENTROPY=m
+# CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE is not set
+# end of Random number generation
+
+#
+# Userspace interface
+#
+CONFIG_CRYPTO_USER_API=m
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
+CONFIG_CRYPTO_USER_API_AEAD=m
+CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
+CONFIG_CRYPTO_STATS=y
+# end of Userspace interface
+
+CONFIG_CRYPTO_HASH_INFO=y
+
+#
+# Accelerated Cryptographic Algorithms for CPU (x86)
+#
+CONFIG_CRYPTO_CURVE25519_X86=m
+CONFIG_CRYPTO_AES_NI_INTEL=m
+CONFIG_CRYPTO_BLOWFISH_X86_64=m
+CONFIG_CRYPTO_CAMELLIA_X86_64=m
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=m
+CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=m
+CONFIG_CRYPTO_CAST5_AVX_X86_64=m
+CONFIG_CRYPTO_CAST6_AVX_X86_64=m
+CONFIG_CRYPTO_DES3_EDE_X86_64=m
+CONFIG_CRYPTO_SERPENT_SSE2_X86_64=m
+CONFIG_CRYPTO_SERPENT_AVX_X86_64=m
+CONFIG_CRYPTO_SERPENT_AVX2_X86_64=m
+# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
+# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
+CONFIG_CRYPTO_TWOFISH_X86_64=m
+CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=m
+CONFIG_CRYPTO_TWOFISH_AVX_X86_64=m
+# CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64 is not set
+# CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64 is not set
+# CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64 is not set
+CONFIG_CRYPTO_CHACHA20_X86_64=m
+CONFIG_CRYPTO_AEGIS128_AESNI_SSE2=m
+CONFIG_CRYPTO_NHPOLY1305_SSE2=m
+CONFIG_CRYPTO_NHPOLY1305_AVX2=m
+CONFIG_CRYPTO_BLAKE2S_X86=y
+# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set
+CONFIG_CRYPTO_POLY1305_X86_64=m
+CONFIG_CRYPTO_SHA1_SSSE3=m
+CONFIG_CRYPTO_SHA256_SSSE3=m
+CONFIG_CRYPTO_SHA512_SSSE3=m
+# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set
+CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m
+CONFIG_CRYPTO_CRC32C_INTEL=m
+CONFIG_CRYPTO_CRC32_PCLMUL=m
+CONFIG_CRYPTO_CRCT10DIF_PCLMUL=m
+# end of Accelerated Cryptographic Algorithms for CPU (x86)
+
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_PADLOCK=m
+CONFIG_CRYPTO_DEV_PADLOCK_AES=m
+CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
+CONFIG_CRYPTO_DEV_ATMEL_I2C=m
+CONFIG_CRYPTO_DEV_ATMEL_ECC=m
+CONFIG_CRYPTO_DEV_ATMEL_SHA204A=m
+CONFIG_CRYPTO_DEV_CCP=y
+CONFIG_CRYPTO_DEV_CCP_DD=m
+CONFIG_CRYPTO_DEV_SP_CCP=y
+CONFIG_CRYPTO_DEV_CCP_CRYPTO=m
+CONFIG_CRYPTO_DEV_SP_PSP=y
+# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
+# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_C62X is not set
+# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
+# CONFIG_CRYPTO_DEV_CHELSIO is not set
+CONFIG_CRYPTO_DEV_VIRTIO=m
+# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
+# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set
+CONFIG_PKCS7_MESSAGE_PARSER=y
+# CONFIG_PKCS7_TEST_KEY is not set
+CONFIG_SIGNED_PE_FILE_VERIFICATION=y
+# CONFIG_FIPS_SIGNATURE_SELFTEST is not set
+
+#
+# Certificates for signature checking
+#
+CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
+CONFIG_MODULE_SIG_KEY_TYPE_RSA=y
+# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
+# CONFIG_SECONDARY_TRUSTED_KEYRING is not set
+# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
+# end of Certificates for signature checking
+
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=y
+CONFIG_RAID6_PQ_BENCHMARK=y
+CONFIG_LINEAR_RANGES=y
+# CONFIG_PACKING is not set
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_CORDIC=m
+# CONFIG_PRIME_NUMBERS is not set
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
+CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
+
+#
+# Crypto library routines
+#
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_ARC4=m
+CONFIG_CRYPTO_LIB_GF128MUL=y
+CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=m
+CONFIG_CRYPTO_LIB_CHACHA_GENERIC=m
+CONFIG_CRYPTO_LIB_CHACHA=m
+CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_DES=m
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11
+CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_POLY1305_GENERIC=m
+CONFIG_CRYPTO_LIB_POLY1305=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_SHA256=y
+# end of Crypto library routines
+
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC64_ROCKSOFT=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC64=y
+# CONFIG_CRC4 is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+CONFIG_CRC8=m
+CONFIG_XXHASH=y
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_842_COMPRESS=m
+CONFIG_842_DECOMPRESS=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_COMPRESS=m
+CONFIG_LZ4HC_COMPRESS=m
+CONFIG_LZ4_DECOMPRESS=m
+CONFIG_ZSTD_COMMON=y
+CONFIG_ZSTD_COMPRESS=m
+CONFIG_ZSTD_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_MICROLZMA is not set
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_ZSTD=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_BTREE=y
+CONFIG_INTERVAL_TREE=y
+CONFIG_XARRAY_MULTI=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAS_DMA=y
+CONFIG_DMA_OPS=y
+CONFIG_NEED_SG_DMA_FLAGS=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_SWIOTLB=y
+# CONFIG_SWIOTLB_DYNAMIC is not set
+# CONFIG_DMA_CMA is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_DMA_MAP_BENCHMARK is not set
+CONFIG_SGL_ALLOC=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_CHECK_SIGNATURE=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_GLOB=y
+# CONFIG_GLOB_SELFTEST is not set
+CONFIG_NLATTR=y
+CONFIG_CLZ_TAB=y
+CONFIG_IRQ_POLL=y
+CONFIG_MPILIB=y
+CONFIG_DIMLIB=y
+CONFIG_OID_REGISTRY=y
+CONFIG_UCS2_STRING=y
+CONFIG_HAVE_GENERIC_VDSO=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_VDSO_TIME_NS=y
+CONFIG_FONT_SUPPORT=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_SG_POOL=y
+CONFIG_ARCH_HAS_PMEM_API=y
+CONFIG_MEMREGION=y
+CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y
+CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
+CONFIG_ARCH_HAS_COPY_MC=y
+CONFIG_ARCH_STACKWALK=y
+CONFIG_SBITMAP=y
+CONFIG_PARMAN=m
+CONFIG_OBJAGG=m
+# end of Library routines
+
+CONFIG_PLDMFW=y
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_CALLER is not set
+# CONFIG_STACKTRACE_BUILD_ID is not set
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
+CONFIG_CONSOLE_LOGLEVEL_QUIET=4
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+CONFIG_BOOT_PRINTK_DELAY=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DYNAMIC_DEBUG_CORE=y
+CONFIG_SYMBOLIC_ERRNAME=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# end of printk and dmesg options
+
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_MISC is not set
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_AS_HAS_NON_CONST_LEB128=y
+CONFIG_DEBUG_INFO_NONE=y
+# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+# CONFIG_DEBUG_INFO_DWARF5 is not set
+CONFIG_FRAME_WARN=2048
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_READABLE_ASM is not set
+# CONFIG_HEADERS_INSTALL is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
+CONFIG_OBJTOOL=y
+# CONFIG_VMLINUX_MAP is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# end of Compile-time checks and compiler options
+
+#
+# Generic Kernel Debugging Instruments
+#
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6
+CONFIG_MAGIC_SYSRQ_SERIAL=y
+CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_FS_ALLOW_ALL=y
+# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
+# CONFIG_DEBUG_FS_ALLOW_NONE is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_UBSAN is not set
+CONFIG_HAVE_ARCH_KCSAN=y
+CONFIG_HAVE_KCSAN_COMPILER=y
+# CONFIG_KCSAN is not set
+# end of Generic Kernel Debugging Instruments
+
+#
+# Networking Debugging
+#
+# CONFIG_NET_DEV_REFCNT_TRACKER is not set
+# CONFIG_NET_NS_REFCNT_TRACKER is not set
+# CONFIG_DEBUG_NET is not set
+# end of Networking Debugging
+
+#
+# Memory Debugging
+#
+CONFIG_PAGE_EXTENSION=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_PAGE_TABLE_CHECK is not set
+CONFIG_PAGE_POISONING=y
+# CONFIG_DEBUG_PAGE_REF is not set
+# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_ARCH_HAS_DEBUG_WX=y
+CONFIG_DEBUG_WX=y
+CONFIG_GENERIC_PTDUMP=y
+CONFIG_PTDUMP_CORE=y
+# CONFIG_PTDUMP_DEBUGFS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_PER_VMA_LOCK_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SHRINKER_DEBUG is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VM_PGTABLE is not set
+CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
+# CONFIG_DEBUG_VIRTUAL is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y
+# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set
+CONFIG_HAVE_ARCH_KASAN=y
+CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
+CONFIG_CC_HAS_KASAN_GENERIC=y
+CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
+# CONFIG_KASAN is not set
+CONFIG_HAVE_ARCH_KFENCE=y
+# CONFIG_KFENCE is not set
+CONFIG_HAVE_ARCH_KMSAN=y
+# end of Memory Debugging
+
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Oops, Lockups and Hangs
+#
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y
+CONFIG_HARDLOCKUP_DETECTOR=y
+# CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY is not set
+CONFIG_HARDLOCKUP_DETECTOR_PERF=y
+# CONFIG_HARDLOCKUP_DETECTOR_BUDDY is not set
+# CONFIG_HARDLOCKUP_DETECTOR_ARCH is not set
+CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER=y
+CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+# CONFIG_WQ_WATCHDOG is not set
+# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set
+# CONFIG_TEST_LOCKUP is not set
+# end of Debug Oops, Lockups and Hangs
+
+#
+# Scheduler Debugging
+#
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHED_INFO=y
+CONFIG_SCHEDSTATS=y
+# end of Scheduler Debugging
+
+# CONFIG_DEBUG_TIMEKEEPING is not set
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_SCF_TORTURE_TEST is not set
+# CONFIG_CSD_LOCK_WAIT_DEBUG is not set
+# end of Lock Debugging (spinlocks, mutexes, etc...)
+
+# CONFIG_NMI_CHECK_CPU is not set
+# CONFIG_DEBUG_IRQFLAGS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
+# CONFIG_DEBUG_KOBJECT is not set
+
+#
+# Debug kernel data structures
+#
+CONFIG_DEBUG_LIST=y
+# CONFIG_DEBUG_PLIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_MAPLE_TREE is not set
+# end of Debug kernel data structures
+
+#
+# RCU Debugging
+#
+# CONFIG_RCU_SCALE_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_REF_SCALE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
+# CONFIG_RCU_CPU_STALL_CPUTIME is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_EQS_DEBUG is not set
+# end of RCU Debugging
+
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
+# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_RETHOOK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
+CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_FENTRY=y
+CONFIG_HAVE_OBJTOOL_MCOUNT=y
+CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_BOOTTIME_TRACING is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_HWLAT_TRACER is not set
+# CONFIG_OSNOISE_TRACER is not set
+# CONFIG_TIMERLAT_TRACER is not set
+# CONFIG_MMIOTRACE is not set
+# CONFIG_FTRACE_SYSCALLS is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_UPROBE_EVENTS=y
+CONFIG_BPF_EVENTS=y
+CONFIG_DYNAMIC_EVENTS=y
+CONFIG_PROBE_EVENTS=y
+# CONFIG_SYNTH_EVENTS is not set
+# CONFIG_USER_EVENTS is not set
+# CONFIG_HIST_TRIGGERS is not set
+# CONFIG_TRACE_EVENT_INJECT is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_TRACE_EVAL_MAP_FILE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
+# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
+# CONFIG_RV is not set
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
+CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_IO_STRICT_DEVMEM=y
+
+#
+# x86 Debugging
+#
+# CONFIG_X86_VERBOSE_BOOTUP is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_EFI_PGT_DUMP is not set
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+# CONFIG_X86_DECODER_SELFTEST is not set
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+# CONFIG_DEBUG_BOOT_PARAMS is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_DEBUG_ENTRY is not set
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+# CONFIG_X86_DEBUG_FPU is not set
+# CONFIG_PUNIT_ATOM_DEBUG is not set
+CONFIG_UNWINDER_ORC=y
+# CONFIG_UNWINDER_FRAME_POINTER is not set
+# CONFIG_UNWINDER_GUESS is not set
+# end of x86 Debugging
+
+#
+# Kernel Testing and Coverage
+#
+# CONFIG_KUNIT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_ARCH_HAS_KCOV=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+# CONFIG_KCOV is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
+CONFIG_ARCH_USE_MEMTEST=y
+# CONFIG_MEMTEST is not set
+# CONFIG_HYPERV_TESTING is not set
+# end of Kernel Testing and Coverage
+
+#
+# Rust hacking
+#
+# end of Rust hacking
+# end of Kernel hacking
diff --git a/scripts/package-build/linux-kernel/build-accel-ppp.sh b/scripts/package-build/linux-kernel/build-accel-ppp.sh
index 1685ff8d..a2f8df52 100755
--- a/scripts/package-build/linux-kernel/build-accel-ppp.sh
+++ b/scripts/package-build/linux-kernel/build-accel-ppp.sh
@@ -13,6 +13,10 @@ if [ ! -f ${KERNEL_VAR_FILE} ]; then
exit 1
fi
+cd ${ACCEL_SRC}
+git reset --hard HEAD
+git clean --force -d -x
+
PATCH_DIR=${CWD}/patches/accel-ppp
if [ -d $PATCH_DIR ]; then
cd ${ACCEL_SRC}
@@ -36,6 +40,10 @@ cmake -DBUILD_IPOE_DRIVER=TRUE \
-DMODULES_KDIR=${KERNEL_VERSION}${KERNEL_SUFFIX} \
-DCPACK_TYPE=Debian12 ..
make
+
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh .
+
cpack -G DEB
# rename resulting Debian package according git description
diff --git a/scripts/package-build/linux-kernel/build-intel-ixgbe.sh b/scripts/package-build/linux-kernel/build-intel-ixgbe.sh
deleted file mode 100755
index 5f45c62a..00000000
--- a/scripts/package-build/linux-kernel/build-intel-ixgbe.sh
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/bin/sh
-CWD=$(pwd)
-KERNEL_VAR_FILE=${CWD}/kernel-vars
-
-if ! dpkg-architecture -iamd64; then
- echo "Intel ixgbe is only buildable on amd64 platforms"
- exit 0
-fi
-
-if [ ! -f ${KERNEL_VAR_FILE} ]; then
- echo "Kernel variable file '${KERNEL_VAR_FILE}' does not exist, run ./build_kernel.sh first"
- exit 1
-fi
-
-. ${KERNEL_VAR_FILE}
-
-url="https://sourceforge.net/projects/e1000/files/ixgbe%20stable/5.20.3/ixgbe-5.20.3.tar.gz"
-
-cd ${CWD}
-
-DRIVER_FILE=$(basename ${url} | sed -e s/tar_0/tar/)
-DRIVER_DIR="${DRIVER_FILE%.tar.gz}"
-DRIVER_NAME="ixgbe"
-DRIVER_VERSION=$(echo ${DRIVER_DIR} | awk -F${DRIVER_NAME} '{print $2}' | sed 's/^-//')
-DRIVER_VERSION_EXTRA=""
-
-# Build up Debian related variables required for packaging
-DEBIAN_ARCH=$(dpkg --print-architecture)
-DEBIAN_DIR="${CWD}/vyos-intel-${DRIVER_NAME}_${DRIVER_VERSION}_${DEBIAN_ARCH}"
-DEBIAN_CONTROL="${DEBIAN_DIR}/DEBIAN/control"
-DEBIAN_POSTINST="${CWD}/vyos-intel-ixgbe.postinst"
-
-# Fetch Intel driver source from SourceForge
-if [ -e ${DRIVER_FILE} ]; then
- rm -f ${DRIVER_FILE}
-fi
-curl -L -o ${DRIVER_FILE} ${url}
-if [ "$?" -ne "0" ]; then
- exit 1
-fi
-
-# Unpack archive
-if [ -d ${DRIVER_DIR} ]; then
- rm -rf ${DRIVER_DIR}
-fi
-mkdir -p ${DRIVER_DIR}
-tar -C ${DRIVER_DIR} --strip-components=1 -xf ${DRIVER_FILE}
-
-cd ${DRIVER_DIR}/src
-if [ -z $KERNEL_DIR ]; then
- echo "KERNEL_DIR not defined"
- exit 1
-fi
-
-# See https://lore.kernel.org/lkml/f90837d0-810e-5772-7841-28d47c44d260@intel.com/
-echo "I: remove pci_enable_pcie_error_reporting() code no longer present in Kernel"
-sed -i '/.*pci_disable_pcie_error_reporting(pdev);/d' ixgbe_main.c
-sed -i '/.*pci_enable_pcie_error_reporting(pdev);/d' ixgbe_main.c
-
-# See https://vyos.dev/T6155
-echo "I: always enable allow_unsupported_sfp for all NICs by default"
-patch -l -p1 < ../../patches/ixgbe/allow_unsupported_sfp.patch
-
-# See https://vyos.dev/T6162
-echo "I: add 1000BASE-BX support"
-patch -l -p1 < ../../patches/ixgbe/add_1000base-bx_support.patch
-
-echo "I: Compile Kernel module for Intel ${DRIVER_NAME} driver"
-make KSRC=${KERNEL_DIR} INSTALL_MOD_PATH=${DEBIAN_DIR} INSTALL_FW_PATH=${DEBIAN_DIR} -j $(getconf _NPROCESSORS_ONLN) install
-
-if [ "x$?" != "x0" ]; then
- exit 1
-fi
-
-if [ -f ${DEBIAN_DIR}.deb ]; then
- rm ${DEBIAN_DIR}.deb
-fi
-
-# build Debian package
-echo "I: Building Debian package vyos-intel-${DRIVER_NAME}"
-cd ${CWD}
-
-# delete non required files which are also present in the kernel package
-# und thus lead to duplicated files
-find ${DEBIAN_DIR} -name "modules.*" | xargs rm -f
-
-echo "#!/bin/sh" > ${DEBIAN_POSTINST}
-echo "/sbin/depmod -a ${KERNEL_VERSION}${KERNEL_SUFFIX}" >> ${DEBIAN_POSTINST}
-
-fpm --input-type dir --output-type deb --name vyos-intel-${DRIVER_NAME} \
- --version ${DRIVER_VERSION} --deb-compression gz \
- --maintainer "VyOS Package Maintainers <maintainers@vyos.net>" \
- --description "Vendor based driver for Intel ${DRIVER_NAME}" \
- --depends linux-image-${KERNEL_VERSION}${KERNEL_SUFFIX} \
- --license "GPL2" -C ${DEBIAN_DIR} --after-install ${DEBIAN_POSTINST}
-
-echo "I: Cleanup ${DRIVER_NAME} source"
-cd ${CWD}
-if [ -e ${DRIVER_FILE} ]; then
- rm -f ${DRIVER_FILE}
-fi
-if [ -d ${DRIVER_DIR} ]; then
- rm -rf ${DRIVER_DIR}
-fi
-if [ -d ${DEBIAN_DIR} ]; then
- rm -rf ${DEBIAN_DIR}
-fi
diff --git a/scripts/package-build/linux-kernel/build-intel-ixgbevf.sh b/scripts/package-build/linux-kernel/build-intel-nic.sh
index a965e0de..3e8bbb37 100755
--- a/scripts/package-build/linux-kernel/build-intel-ixgbevf.sh
+++ b/scripts/package-build/linux-kernel/build-intel-nic.sh
@@ -3,7 +3,7 @@ CWD=$(pwd)
KERNEL_VAR_FILE=${CWD}/kernel-vars
if ! dpkg-architecture -iamd64; then
- echo "Intel ixgbevf is only buildable on amd64 platforms"
+ echo "Intel drivers only buildable on amd64 platforms"
exit 0
fi
@@ -14,51 +14,39 @@ fi
. ${KERNEL_VAR_FILE}
-url="https://sourceforge.net/projects/e1000/files/ixgbevf%20stable/4.18.9/ixgbevf-4.18.9.tar.gz"
+if [ -z $KERNEL_DIR ]; then
+ echo "KERNEL_DIR not defined"
+ exit 1
+fi
-cd ${CWD}
+DRIVER_NAME=$1
+cd ${CWD}/ethernet-linux-${DRIVER_NAME}
+if [ -d .git ]; then
+ git clean --force -d -x
+ git reset --hard origin/main
+fi
-DRIVER_FILE=$(basename ${url} | sed -e s/tar_0/tar/)
-DRIVER_DIR="${DRIVER_FILE%.tar.gz}"
-DRIVER_NAME="ixgbevf"
-DRIVER_VERSION=$(echo ${DRIVER_DIR} | awk -F${DRIVER_NAME} '{print $2}' | sed 's/^-//')
-DRIVER_VERSION_EXTRA=""
+DRIVER_VERSION=$(git describe | sed s/^v//)
# Build up Debian related variables required for packaging
DEBIAN_ARCH=$(dpkg --print-architecture)
DEBIAN_DIR="${CWD}/vyos-intel-${DRIVER_NAME}_${DRIVER_VERSION}_${DEBIAN_ARCH}"
DEBIAN_CONTROL="${DEBIAN_DIR}/DEBIAN/control"
-DEBIAN_POSTINST="${CWD}/vyos-intel-ixgbevf.postinst"
-
-# Fetch Intel driver source from SourceForge
-if [ -e ${DRIVER_FILE} ]; then
- rm -f ${DRIVER_FILE}
-fi
-curl -L -o ${DRIVER_FILE} ${url}
-if [ "$?" -ne "0" ]; then
- exit 1
-fi
-
-# Unpack archive
-if [ -d ${DRIVER_DIR} ]; then
- rm -rf ${DRIVER_DIR}
-fi
-mkdir -p ${DRIVER_DIR}
-tar -C ${DRIVER_DIR} --strip-components=1 -xf ${DRIVER_FILE}
-
-cd ${DRIVER_DIR}/src
-if [ -z $KERNEL_DIR ]; then
- echo "KERNEL_DIR not defined"
- exit 1
+DEBIAN_POSTINST="${CWD}/vyos-intel-${DRIVER_NAME}.postinst"
+
+# See https://vyos.dev/T6155
+# See https://vyos.dev/T6162
+PATCH_DIR=${CWD}/patches/${DRIVER_NAME}
+if [ -d $PATCH_DIR ]; then
+ for patch in $(ls ${PATCH_DIR})
+ do
+ echo "I: Apply patch: ${PATCH_DIR}/${patch}"
+ patch -p1 < ${PATCH_DIR}/${patch}
+ done
fi
-# See https://lore.kernel.org/lkml/f90837d0-810e-5772-7841-28d47c44d260@intel.com/
-echo "I: remove pci_enable_pcie_error_reporting() code no longer present in Kernel"
-sed -i '/.*pci_disable_pcie_error_reporting(pdev);/d' ixgbevf_main.c
-sed -i '/.*pci_enable_pcie_error_reporting(pdev);/d' ixgbevf_main.c
-
echo "I: Compile Kernel module for Intel ${DRIVER_NAME} driver"
-make KSRC=${KERNEL_DIR} INSTALL_MOD_PATH=${DEBIAN_DIR} INSTALL_FW_PATH=${DEBIAN_DIR} -j $(getconf _NPROCESSORS_ONLN) install
+make KSRC=${KERNEL_DIR} INSTALL_MOD_PATH=${DEBIAN_DIR} INSTALL_FW_PATH=${DEBIAN_DIR} -j $(getconf _NPROCESSORS_ONLN) -C src install
if [ "x$?" != "x0" ]; then
exit 1
@@ -72,6 +60,9 @@ fi
echo "I: Building Debian package vyos-intel-${DRIVER_NAME}"
cd ${CWD}
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${DEBIAN_DIR}
+
# delete non required files which are also present in the kernel package
# und thus lead to duplicated files
find ${DEBIAN_DIR} -name "modules.*" | xargs rm -f
@@ -85,16 +76,3 @@ fpm --input-type dir --output-type deb --name vyos-intel-${DRIVER_NAME} \
--description "Vendor based driver for Intel ${DRIVER_NAME}" \
--depends linux-image-${KERNEL_VERSION}${KERNEL_SUFFIX} \
--license "GPL2" -C ${DEBIAN_DIR} --after-install ${DEBIAN_POSTINST}
-
-echo "I: Cleanup ${DRIVER_NAME} source"
-cd ${CWD}
-if [ -e ${DRIVER_FILE} ]; then
- rm -f ${DRIVER_FILE}
-fi
-if [ -d ${DRIVER_DIR} ]; then
- rm -rf ${DRIVER_DIR}
-fi
-if [ -d ${DEBIAN_DIR} ]; then
- rm -rf ${DEBIAN_DIR}
-fi
-
diff --git a/scripts/package-build/linux-kernel/build-intel-qat.sh b/scripts/package-build/linux-kernel/build-intel-qat.sh
index 765cea3f..c2c364a9 100755
--- a/scripts/package-build/linux-kernel/build-intel-qat.sh
+++ b/scripts/package-build/linux-kernel/build-intel-qat.sh
@@ -14,7 +14,7 @@ fi
. ${KERNEL_VAR_FILE}
-url="https://dev.packages.vyos.net/source-mirror/QAT.L.4.24.0-00005.tar.gz"
+url="https://packages.vyos.net/source-mirror/QAT.L.4.24.0-00005.tar.gz"
cd ${CWD}
@@ -84,6 +84,9 @@ fi
echo "I: Building Debian package vyos-intel-${DRIVER_NAME}"
cd ${CWD}
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${DEBIAN_DIR}
+
# delete non required files which are also present in the kernel package
# und thus lead to duplicated files
find ${DEBIAN_DIR} -name "modules.*" | xargs rm -f
@@ -98,14 +101,17 @@ fpm --input-type dir --output-type deb --name vyos-intel-${DRIVER_NAME} \
--depends linux-image-${KERNEL_VERSION}${KERNEL_SUFFIX} \
--license "GPL2" -C ${DEBIAN_DIR} --after-install ${DEBIAN_POSTINST}
-echo "I: Cleanup ${DRIVER_NAME} source"
-cd ${CWD}
-if [ -e ${DRIVER_FILE} ]; then
- rm -f ${DRIVER_FILE}
-fi
-if [ -d ${DRIVER_DIR} ]; then
- rm -rf ${DRIVER_DIR}
-fi
-if [ -d ${DEBIAN_DIR} ]; then
- rm -rf ${DEBIAN_DIR}
-fi
+# echo "I: Cleanup ${DRIVER_NAME} source"
+# cd ${CWD}
+# if [ -e ${DRIVER_FILE} ]; then
+# rm -f ${DRIVER_FILE}
+# fi
+# if [ -d ${DRIVER_DIR} ]; then
+# rm -rf ${DRIVER_DIR}
+# fi
+# if [ -d ${DEBIAN_DIR} ]; then
+# rm -rf ${DEBIAN_DIR}
+# fi
+# if [ -f ${DEBIAN_POSTINST} ]; then
+# rm -f ${DEBIAN_POSTINST}
+# fi
diff --git a/scripts/package-build/linux-kernel/build-ipt-netflow.sh b/scripts/package-build/linux-kernel/build-ipt-netflow.sh
new file mode 100755
index 00000000..9245a416
--- /dev/null
+++ b/scripts/package-build/linux-kernel/build-ipt-netflow.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+CWD=$(pwd)
+KERNEL_VAR_FILE=${CWD}/kernel-vars
+
+IPT_NETFLOW_SRC=${CWD}/ipt-netflow
+if [ ! -d ${IPT_NETFLOW_SRC} ]; then
+ echo "ipt_NETFLOW source not found"
+ exit 1
+fi
+
+if [ ! -f ${KERNEL_VAR_FILE} ]; then
+ echo "Kernel variable file '${KERNEL_VAR_FILE}' does not exist, run ./build_kernel.sh first"
+ exit 1
+fi
+
+cd ${IPT_NETFLOW_SRC}
+if [ -d .git ]; then
+ git reset --hard HEAD
+ git clean --force -d -x
+fi
+
+. ${KERNEL_VAR_FILE}
+
+DRIVER_VERSION=$(git describe | sed s/^v//)
+
+# Build up Debian related variables required for packaging
+DEBIAN_ARCH=$(dpkg --print-architecture)
+DEBIAN_DIR="tmp/"
+DEBIAN_CONTROL="${DEBIAN_DIR}/DEBIAN/control"
+DEBIAN_POSTINST="${CWD}/vyos-ipt-netflow.postinst"
+
+./configure --enable-aggregation --kdir=${KERNEL_DIR}
+make all
+
+if [ "x$?" != "x0" ]; then
+ exit 1
+fi
+
+if [ -f ${DEBIAN_DIR}.deb ]; then
+ rm ${DEBIAN_DIR}.deb
+fi
+
+if [ ! -d ${DEBIAN_DIR} ]; then
+ mkdir -p ${DEBIAN_DIR}
+fi
+
+# build Debian package
+echo "I: Building Debian package vyos-ipt-netflow"
+cp ipt_NETFLOW.ko ${DEBIAN_DIR}
+cp libipt_NETFLOW.so ${DEBIAN_DIR}
+cp libip6t_NETFLOW.so ${DEBIAN_DIR}
+
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${DEBIAN_DIR}
+
+echo "#!/bin/sh" > ${DEBIAN_POSTINST}
+echo "/sbin/depmod -a ${KERNEL_VERSION}${KERNEL_SUFFIX}" >> ${DEBIAN_POSTINST}
+
+cd ${CWD}
+
+fpm --input-type dir --output-type deb --name vyos-ipt-netflow \
+ --version ${DRIVER_VERSION} --deb-compression gz \
+ --maintainer "VyOS Package Maintainers <maintainers@vyos.net>" \
+ --description "ipt_NETFLOW module" \
+ --depends linux-image-${KERNEL_VERSION}${KERNEL_SUFFIX} \
+ --license "GPL2" -C ${IPT_NETFLOW_SRC}/tmp --after-install ${DEBIAN_POSTINST} \
+ ipt_NETFLOW.ko=/lib/modules/${KERNEL_VERSION}${KERNEL_SUFFIX}/extra/ipt_NETFLOW.ko \
+ libipt_NETFLOW.so=/lib/$(uname -m)-linux-gnu/xtables/libipt_NETFLOW.so \
+ libip6t_NETFLOW.so=/lib/$(uname -m)-linux-gnu/xtables/libip6t_NETFLOW.so
diff --git a/scripts/package-build/linux-kernel/build-jool.py b/scripts/package-build/linux-kernel/build-jool.py
index 570293f5..3d2c3d6a 100755
--- a/scripts/package-build/linux-kernel/build-jool.py
+++ b/scripts/package-build/linux-kernel/build-jool.py
@@ -29,9 +29,8 @@ def add_depends(package_dir: str, package_name: str,
# find kernel version and source path
arch: str = find_arch()
defaults_file: str = Path('../../../data/defaults.toml').read_text()
-architecture_file: str = Path(f'../../../data/architectures/{arch}.toml').read_text()
KERNEL_VER: str = toml_loads(defaults_file).get('kernel_version')
-KERNEL_FLAVOR: str = toml_loads(architecture_file).get('kernel_flavor')
+KERNEL_FLAVOR: str = toml_loads(defaults_file).get('kernel_flavor')
KERNEL_SRC: str = Path.cwd().as_posix() + '/linux'
# define variables
@@ -66,7 +65,7 @@ MODULES_DIR := extra
# main packaging script based on dh7 syntax
%:
- dh $@
+ dh $@
override_dh_clean:
dh_clean --exclude=debian/{PACKAGE_NAME}.substvars
@@ -88,7 +87,7 @@ override_dh_auto_install:
install -D -m 644 src/mod/common/jool_common.ko ${{PACKAGE_BUILD_DIR}}/lib/modules/${{KVER}}/${{MODULES_DIR}}/jool_common.ko
install -D -m 644 src/mod/nat64/jool.ko ${{PACKAGE_BUILD_DIR}}/lib/modules/${{KVER}}/${{MODULES_DIR}}/jool.ko
install -D -m 644 src/mod/siit/jool_siit.ko ${{PACKAGE_BUILD_DIR}}/lib/modules/${{KVER}}/${{MODULES_DIR}}/jool_siit.ko
-
+ ${{KERNEL_DIR}}/../sign-modules.sh ${{PACKAGE_BUILD_DIR}}/lib
'''
bild_rules = Path(f'{PACKAGE_DIR}/debian/rules')
bild_rules.write_text(build_rules_text)
diff --git a/scripts/package-build/linux-kernel/build-kernel.sh b/scripts/package-build/linux-kernel/build-kernel.sh
index 2c02f5c3..62dd7829 100755
--- a/scripts/package-build/linux-kernel/build-kernel.sh
+++ b/scripts/package-build/linux-kernel/build-kernel.sh
@@ -9,16 +9,20 @@ if [ ! -d ${KERNEL_SRC} ]; then
exit 1
fi
-echo "I: Copy Kernel config (x86_64_vyos_defconfig) to Kernel Source"
-cp -rv arch/ ${KERNEL_SRC}/
-
cd ${KERNEL_SRC}
-echo "I: clean modified files"
-git reset --hard HEAD
+if [ -d .git ]; then
+ echo "I: Clean modified files - reset Git repo"
+ git reset --hard HEAD
+ git clean --force -d -x
+fi
+
+echo "I: Copy Kernel config (x86_64_vyos_defconfig) to Kernel Source"
+cp -rv ${CWD}/arch/ .
KERNEL_VERSION=$(make kernelversion)
-KERNEL_SUFFIX=-$(dpkg --print-architecture)-vyos
+KERNEL_SUFFIX=-$(awk -F "= " '/kernel_flavor/ {print $2}' ../../../../data/defaults.toml | tr -d \")
+KERNEL_CONFIG=arch/x86/configs/vyos_defconfig
# VyOS requires some small Kernel Patches - apply them here
# It's easier to habe them here and make use of the upstream
@@ -31,26 +35,54 @@ do
patch -p1 < ${PATCH_DIR}/${patch}
done
+# Change name of Signing Cert
+sed -i -e "s/CN =.*/CN=VyOS Networks build time autogenerated Kernel key/" certs/default_x509.genkey
+
+TRUSTED_KEYS_FILE=trusted_keys.pem
+# start with empty key file
+echo -n "" > $TRUSTED_KEYS_FILE
+GIT_ROOT=$(git rev-parse --show-toplevel)
+CERTS=$(find ${GIT_ROOT}/data/certificates -name "*.pem" -type f || true)
+if [ ! -z "${CERTS}" ]; then
+ # add known public keys to Kernel certificate chain
+ for file in $CERTS; do
+ cat $file >> $TRUSTED_KEYS_FILE
+ done
+ # Force Kernel module signing and embed public keys
+ echo "CONFIG_SYSTEM_TRUSTED_KEYRING" >> $KERNEL_CONFIG
+ echo "CONFIG_SYSTEM_TRUSTED_KEYS=\"$TRUSTED_KEYS_FILE\"" >> $KERNEL_CONFIG
+fi
+
echo "I: make vyos_defconfig"
# Select Kernel configuration - currently there is only one
make vyos_defconfig
echo "I: Generate environment file containing Kernel variable"
+EPHEMERAL_KEY="/tmp/ephemeral.key"
+EPHEMERAL_PEM="/tmp/ephemeral.pem"
cat << EOF >${CWD}/kernel-vars
#!/bin/sh
export KERNEL_VERSION=${KERNEL_VERSION}
export KERNEL_SUFFIX=${KERNEL_SUFFIX}
export KERNEL_DIR=${CWD}/${KERNEL_SRC}
+export EPHEMERAL_KEY=${EPHEMERAL_KEY}
+export EPHEMERAL_CERT=${EPHEMERAL_PEM}
EOF
echo "I: Build Debian Kernel package"
touch .scmversion
make bindeb-pkg BUILD_TOOLS=1 LOCALVERSION=${KERNEL_SUFFIX} KDEB_PKGVERSION=${KERNEL_VERSION}-1 -j $(getconf _NPROCESSORS_ONLN)
+# Back to the old Kernel build-scripts directory
cd $CWD
-if [[ $? == 0 ]]; then
- for package in $(ls linux-*.deb)
- do
- ln -sf linux-kernel/$package ..
- done
+EPHEMERAL_KERNEL_KEY=$(grep -E "^CONFIG_MODULE_SIG_KEY=" ${KERNEL_SRC}/$KERNEL_CONFIG | awk -F= '{print $2}' | tr -d \")
+if test -f "${EPHEMERAL_KEY}"; then
+ rm -f ${EPHEMERAL_KEY}
+fi
+if test -f "${EPHEMERAL_PEM}"; then
+ rm -f ${EPHEMERAL_PEM}
+fi
+if test -f "${KERNEL_SRC}/${EPHEMERAL_KERNEL_KEY}"; then
+ openssl rsa -in ${KERNEL_SRC}/${EPHEMERAL_KERNEL_KEY} -out ${EPHEMERAL_KEY}
+ openssl x509 -in ${KERNEL_SRC}/${EPHEMERAL_KERNEL_KEY} -out ${EPHEMERAL_PEM}
fi
diff --git a/scripts/package-build/linux-kernel/build-mellanox-ofed.sh b/scripts/package-build/linux-kernel/build-mellanox-ofed.sh
new file mode 100755
index 00000000..3f8a50f0
--- /dev/null
+++ b/scripts/package-build/linux-kernel/build-mellanox-ofed.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+DROP_DEV_DBG_DEBS=1
+DEB_DISTRO='debian12.1'
+CWD=$(pwd)
+KERNEL_VAR_FILE=${CWD}/kernel-vars
+
+if [ $(id -u) -ne 0 ]; then
+ echo "Mellanox OFED script needs to be run as root"
+ exit
+fi
+
+if ! dpkg-architecture -iamd64; then
+ echo "Mellanox OFED is only buildable on amd64 platforms"
+ exit 0
+fi
+
+if [ ! -f ${KERNEL_VAR_FILE} ]; then
+ echo "Kernel variable file '${KERNEL_VAR_FILE}' does not exist, run ./build_kernel.sh first"
+ exit 1
+fi
+
+. ${KERNEL_VAR_FILE}
+
+mlxver="24.07-0.6.1.0"
+url="https://www.mellanox.com/downloads/ofed/MLNX_OFED-${mlxver}/MLNX_OFED_SRC-debian-${mlxver}.tgz"
+
+cd ${CWD}
+
+DRIVER_FILE=$(basename ${url} | sed -e s/tar_0/tar/)
+DRIVER_SHA1="c64defa8fb38dcbce153adc09834ab5cdcecd791"
+
+DRIVER_DIR="${DRIVER_FILE%.tgz}"
+DRIVER_NAME="ofed"
+DRIVER_PRFX="MLNX_OFED"
+DRIVER_VERSION=$(echo ${DRIVER_DIR} | awk -F${DRIVER_PRFX} '{print $2}' | sed 's/^-//;s|_SRC-debian-||')
+DRIVER_VERSION_EXTRA=""
+
+# Build up Debian related variables required for packaging
+DEBIAN_ARCH=$(dpkg --print-architecture)
+DEBIAN_DIR="${CWD}/vyos-mellanox-${DRIVER_NAME}_${DRIVER_VERSION}_${DEBIAN_ARCH}"
+DEBIAN_CONTROL="${DEBIAN_DIR}/DEBIAN/control"
+DEBIAN_POSTINST="${CWD}/vyos-mellanox-ofed.postinst"
+
+# Fetch OFED driver source from Nvidia
+if [ -e ${DRIVER_FILE} ]; then
+ rm -f ${DRIVER_FILE}
+fi
+curl -L -o ${DRIVER_FILE} ${url}
+if [ "$?" -ne "0" ]; then
+ exit 1
+fi
+
+# Verify integrity
+echo "${DRIVER_SHA1} ${DRIVER_FILE}" | sha1sum -c -
+if [ $? != 0 ]; then
+ echo SHA1 checksum missmatch
+ exit 1
+fi
+
+# Unpack archive
+if [ -d ${DRIVER_DIR} ]; then
+ rm -rf ${DRIVER_DIR}
+fi
+mkdir -p ${DRIVER_DIR}
+tar -C ${DRIVER_DIR} --strip-components=1 -xf ${DRIVER_FILE}
+
+# Build/install debs
+cd ${DRIVER_DIR}
+if [ -z $KERNEL_DIR ]; then
+ echo "KERNEL_DIR not defined"
+ exit 1
+fi
+
+rm -f SOURCES/ibarr_*.tar.gz
+rm -f SOURCES/ibdump_*.tar.gz
+rm -f SOURCES/ibsim_*.tar.gz
+rm -f SOURCES/iser_*.tar.gz
+rm -f SOURCES/isert_*.tar.gz
+rm -f SOURCES/kernel-mft_*.tar.gz
+rm -f SOURCES/knem_*.tar.gz
+rm -f SOURCES/libvma_*.tar.gz
+rm -f SOURCES/libxlio_*.tar.gz
+rm -f SOURCES/mlnx-ethtool_*.tar.gz
+rm -f SOURCES/mlnx-iproute2_*.tar.gz
+rm -f SOURCES/mlnx-nfsrdma_*.tar.gz
+rm -f SOURCES/mlnx-nvme_*.tar.gz
+rm -f SOURCES/mlx-steering-dump_*.tar.gz
+rm -f SOURCES/mpitests_*.tar.gz
+rm -f SOURCES/mstflint_*.tar.gz
+rm -f SOURCES/ofed-scripts_*.tar.gz
+rm -f SOURCES/openmpi_*.tar.gz
+rm -f SOURCES/openvswitch_*.tar.gz
+rm -f SOURCES/perftest_*.tar.gz
+rm -f SOURCES/rdma-core_*.tar.gz
+rm -f SOURCES/rshim_*.tar.gz
+rm -f SOURCES/sockperf_*.tar.gz
+rm -f SOURCES/srp_*.tar.gz
+rm -f SOURCES/ucx_*.tar.gz
+
+./install.pl \
+ --basic --dpdk \
+ --without-dkms \
+ --without-mlnx-nvme-modules \
+ --with-vma --vma-vpi --vma-eth \
+ --guest --hypervisor \
+ --builddir ${DEBIAN_DIR}/mlx \
+ --distro ${DEB_DISTRO} \
+ --kernel-sources ${KERNEL_DIR} \
+ --kernel ${KERNEL_VERSION}${KERNEL_SUFFIX}
+
+if [ $DROP_DEV_DBG_DEBS -eq 1 ]; then
+ echo "I: Removing development and debug packages"
+ rm -f $(find $CWD/$DRIVER_DIR/DEBS/$DEB_DISTRO -type f | grep -E '\-dev|\-dbg')
+fi
+
+cp $(find $CWD/$DRIVER_DIR/DEBS/$DEB_DISTRO -type f | grep '\.deb$') "$CWD/"
+
+echo "I: Cleanup ${DRIVER_NAME} source"
+cd ${CWD}
+
+# Sign modules
+DEB_NAME=$(ls mlnx-ofed-kernel-modules_*)
+TMP_DIR="tmp-ofed-sign"
+dpkg-deb --raw-extract ${DEB_NAME} ${TMP_DIR}
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${TMP_DIR}
+# Cleanup and repack DEB
+rm -f ${DEB_NAME}
+dpkg-deb --build ${TMP_DIR} ${DEB_NAME}
+rm -rf ${TMP_DIR}
+
+if [ -f ${DRIVER_FILE} ]; then
+ rm -f ${DRIVER_FILE}
+fi
+if [ -d ${DRIVER_DIR} ]; then
+ rm -rf ${DRIVER_DIR}
+fi
+if [ -d ${DEBIAN_DIR} ]; then
+ rm -rf ${DEBIAN_DIR}
+fi
diff --git a/scripts/package-build/linux-kernel/build-nat-rtsp.sh b/scripts/package-build/linux-kernel/build-nat-rtsp.sh
index ec7d19a6..33f1311d 100755
--- a/scripts/package-build/linux-kernel/build-nat-rtsp.sh
+++ b/scripts/package-build/linux-kernel/build-nat-rtsp.sh
@@ -15,7 +15,10 @@ fi
. ${KERNEL_VAR_FILE}
-cd ${SRC} && make KERNELDIR=$KERNEL_DIR
+cd ${SRC}
+git reset --hard HEAD
+git clean --force -d -x
+make KERNELDIR=$KERNEL_DIR
# Copy binary to package directory
DEBIAN_DIR=tmp/lib/modules/${KERNEL_VERSION}${KERNEL_SUFFIX}/extra
@@ -26,6 +29,9 @@ DEBIAN_POSTINST="${CWD}/vyos-nat-rtsp.postinst"
echo "#!/bin/sh" > ${DEBIAN_POSTINST}
echo "/sbin/depmod -a ${KERNEL_VERSION}${KERNEL_SUFFIX}" >> ${DEBIAN_POSTINST}
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${DEBIAN_DIR}
+
# Build Debian Package
fpm --input-type dir --output-type deb --name nat-rtsp \
--version $(git describe --tags --always) --deb-compression gz \
@@ -36,3 +42,7 @@ fpm --input-type dir --output-type deb --name nat-rtsp \
--license "GPL2" --chdir tmp
mv *.deb ..
+
+if [ -f ${DEBIAN_POSTINST} ]; then
+ rm -f ${DEBIAN_POSTINST}
+fi
diff --git a/scripts/package-build/linux-kernel/build-openvpn-dco.sh b/scripts/package-build/linux-kernel/build-openvpn-dco.sh
index fd427825..518729ee 100755
--- a/scripts/package-build/linux-kernel/build-openvpn-dco.sh
+++ b/scripts/package-build/linux-kernel/build-openvpn-dco.sh
@@ -15,13 +15,19 @@ fi
. ${KERNEL_VAR_FILE}
-cd ${SRC} && make KERNEL_SRC=$KERNEL_DIR
+cd ${SRC}
+git reset --hard HEAD
+git clean --force -d -x
+make KERNEL_SRC=$KERNEL_DIR
# Copy binary to package directory
DEBIAN_DIR=tmp/lib/modules/${KERNEL_VERSION}${KERNEL_SUFFIX}/extra
mkdir -p ${DEBIAN_DIR}
cp drivers/net/ovpn-dco/ovpn-dco-v2.ko ${DEBIAN_DIR}
+# Sign generated Kernel modules
+${CWD}/sign-modules.sh ${DEBIAN_DIR}
+
# Build Debian Package
fpm --input-type dir --output-type deb --name openvpn-dco \
--version $(git describe | sed s/^v//) --deb-compression gz \
diff --git a/scripts/package-build/linux-kernel/build-realtek-r8152.py b/scripts/package-build/linux-kernel/build-realtek-r8152.py
new file mode 100755
index 00000000..0113eafc
--- /dev/null
+++ b/scripts/package-build/linux-kernel/build-realtek-r8152.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+
+import os
+from tomllib import loads as toml_loads
+from requests import get
+from pathlib import Path
+from subprocess import run
+
+CWD = os.getcwd()
+
+# dependency modifier
+def add_depends(package_dir: str, package_name: str,
+ depends: list[str]) -> None:
+ """Add dependencies to a package
+ Args:
+ package_dir (str): a directory where package sources are located
+ package_name (str): a name of package
+ depends (list[str]): a list of dependencies to add
+ """
+ depends_list: str = ', '.join(depends)
+ depends_line: str = f'misc:Depends={depends_list}\n'
+
+ substvars_file = Path(f'{package_dir}/debian/{package_name}.substvars')
+ substvars_file.write_text(depends_line)
+
+
+# find kernel version and source path
+defaults_file: str = Path('../../../data/defaults.toml').read_text()
+architecture_file: str = Path('../../../data/architectures/amd64.toml').read_text()
+KERNEL_VER: str = toml_loads(defaults_file).get('kernel_version')
+KERNEL_FLAVOR: str = toml_loads(defaults_file).get('kernel_flavor')
+KERNEL_SRC: str = Path.cwd().as_posix() + '/linux'
+# define variables
+PACKAGE_NAME: str = 'vyos-drivers-realtek-r8152'
+PACKAGE_VERSION: str = '2.18.1'
+PACKAGE_DIR: str = f'{PACKAGE_NAME}-{PACKAGE_VERSION}'
+SOURCES_ARCHIVE: str = 'r8152-2.18.1.tar.bz2'
+SOURCES_URL: str = f'https://packages.vyos.net/source-mirror/r8152-2.18.1.tar.bz2'
+
+# download sources
+sources_archive = Path(SOURCES_ARCHIVE)
+sources_archive.write_bytes(get(SOURCES_URL).content)
+
+# prepare sources
+debmake_cmd: list[str] = [
+ 'debmake', '-e', 'support@vyos.io', '-f', 'VyOS Support', '-p',
+ PACKAGE_NAME, '-u', PACKAGE_VERSION, '-a', SOURCES_ARCHIVE
+]
+run(debmake_cmd)
+
+# add kernel to dependencies
+add_depends(PACKAGE_DIR, PACKAGE_NAME,
+ [f'linux-image-{KERNEL_VER}-{KERNEL_FLAVOR}'])
+
+# configure build rules
+build_rules_text: str = '''#!/usr/bin/make -f
+# config
+export KERNELDIR := {KERNEL_SRC}
+PACKAGE_BUILD_DIR := debian/{PACKAGE_NAME}
+KVER := {KERNEL_VER}-{KERNEL_FLAVOR}
+MODULES_DIR := updates/drivers/net/usb
+# main packaging script based on dh7 syntax
+%:
+\tdh $@
+
+override_dh_clean:
+\tdh_clean --exclude=debian/{PACKAGE_NAME}.substvars
+
+override_dh_prep:
+\tdh_prep --exclude=debian/{PACKAGE_NAME}.substvars
+
+override_dh_auto_clean:
+\tmake clean
+
+override_dh_auto_build:
+\techo "KERNELDIR=${{KERNELDIR}}"
+\techo "CURDIR=${{CURDIR}}"
+\tmake -C ${{KERNELDIR}} M=${{CURDIR}} modules
+
+override_dh_auto_install:
+\tinstall -D -m 644 r8152.ko ${{PACKAGE_BUILD_DIR}}/lib/modules/${{KVER}}/${{MODULES_DIR}}/r8152.ko
+\t${{KERNELDIR}}/../sign-modules.sh ${{PACKAGE_BUILD_DIR}}/lib
+\tinstall -D -m 644 50-usb-realtek-net.rules ${{PACKAGE_BUILD_DIR}}/etc/udev/rules.d/50-usb-realtek-net.rules
+'''.format(KERNEL_SRC=KERNEL_SRC, PACKAGE_NAME=PACKAGE_NAME, KERNEL_VER=KERNEL_VER, KERNEL_FLAVOR=KERNEL_FLAVOR)
+
+build_rules_path = Path(f'{PACKAGE_DIR}/debian/rules')
+build_rules_path.write_text(build_rules_text, encoding='utf-8')
+
+# build a package
+debuild_cmd: list[str] = ['debuild']
+run(debuild_cmd, cwd=PACKAGE_DIR, check=True)
+
+# Sign generated Kernel modules
+clean_cmd: list[str] = ['rm', '-rf', PACKAGE_DIR]
+run(clean_cmd, cwd=CWD, check=True)
diff --git a/scripts/package-build/linux-kernel/build.py b/scripts/package-build/linux-kernel/build.py
index 1bcab686..af610079 100755
--- a/scripts/package-build/linux-kernel/build.py
+++ b/scripts/package-build/linux-kernel/build.py
@@ -63,6 +63,40 @@ def clone_or_update_repo(repo_dir: Path, scm_url: str, commit_id: str) -> None:
run(['git', 'checkout', commit_id], cwd=repo_dir, check=True)
+def create_tarball(package_name, source_dir=None):
+ """Creates a .tar.gz archive of the specified directory.
+
+ Args:
+ package_name (str): The name of the package. This will also be the name of the output tarball.
+ source_dir (str, optional): The directory to be archived. If not provided, defaults to `package_name`.
+
+ Raises:
+ FileNotFoundError: If the specified `source_dir` does not exist.
+ Exception: If an error occurs during tarball creation.
+
+ Example:
+ >>> create_tarball("linux-6.6.56")
+ I: Tarball created: linux-6.6.56.tar.gz
+
+ >>> create_tarball("my-package", "/path/to/source")
+ I: Tarball created: my-package.tar.gz
+ """
+ # Use package_name as the source directory if source_dir is not provided
+ source_dir = source_dir or package_name
+ output_tarball = f"{package_name}.tar.gz"
+
+ # Check if the source directory exists
+ if not os.path.isdir(source_dir):
+ raise FileNotFoundError(f"Directory '{source_dir}' does not exist.")
+
+ # Create the tarball
+ try:
+ shutil.make_archive(base_name=output_tarball.replace('.tar.gz', ''), format='gztar', root_dir=source_dir)
+ print(f"I: Tarball created: {output_tarball}")
+ except Exception as e:
+ print(f"I: Failed to create tarball for {package_name}: {e}")
+
+
def build_package(package: dict, dependencies: list) -> None:
"""Build a package from the repository
@@ -88,20 +122,32 @@ def build_package(package: dict, dependencies: list) -> None:
# Execute the build command
if package['build_cmd'] == 'build_kernel':
build_kernel(package['kernel_version'])
+ create_tarball(f'{package["name"]}-{package["kernel_version"]}', f'linux-{package["kernel_version"]}')
elif package['build_cmd'] == 'build_linux_firmware':
build_linux_firmware(package['commit_id'], package['scm_url'])
+ create_tarball(f'{package["name"]}-{package["commit_id"]}', f'{package["name"]}')
elif package['build_cmd'] == 'build_accel_ppp':
build_accel_ppp(package['commit_id'], package['scm_url'])
+ create_tarball(f'{package["name"]}-{package["commit_id"]}', f'{package["name"]}')
elif package['build_cmd'] == 'build_intel_qat':
build_intel_qat()
+ elif package['build_cmd'] == 'build_intel_igb':
+ build_intel(package['name'], package['commit_id'], package['scm_url'])
elif package['build_cmd'] == 'build_intel_ixgbe':
- build_intel_ixgbe()
+ build_intel(package['name'], package['commit_id'], package['scm_url'])
elif package['build_cmd'] == 'build_intel_ixgbevf':
- build_intel_ixgbevf()
+ build_intel(package['name'], package['commit_id'], package['scm_url'])
+ elif package['build_cmd'] == 'build_mellanox_ofed':
+ build_mellanox_ofed()
+ elif package['build_cmd'] == 'build_realtek_r8152':
+ build_realtek_r8152()
elif package['build_cmd'] == 'build_jool':
build_jool()
+ elif package['build_cmd'] == 'build_ipt_netflow':
+ build_ipt_netflow(package['commit_id'], package['scm_url'])
elif package['build_cmd'] == 'build_openvpn_dco':
build_openvpn_dco(package['commit_id'], package['scm_url'])
+ create_tarball(f'{package["name"]}-{package["commit_id"]}', f'{package["name"]}')
elif package['build_cmd'] == 'build_nat_rtsp':
build_nat_rtsp(package['commit_id'], package['scm_url'])
else:
@@ -173,20 +219,32 @@ def build_intel_qat():
run(['./build-intel-qat.sh'], check=True)
-def build_intel_ixgbe():
- """Build Intel IXGBE"""
- run(['./build-intel-ixgbe.sh'], check=True)
+def build_intel(driver_name: str, commit_id: str, scm_url: str):
+ """Build Intel driver from Git repository"""
+ repo_dir = Path(f'ethernet-linux-{driver_name}')
+ clone_or_update_repo(repo_dir, scm_url, commit_id)
+ run(['./build-intel-nic.sh', driver_name], check=True)
+
+def build_mellanox_ofed():
+ """Build Mellanox OFED"""
+ run(['sudo', './build-mellanox-ofed.sh'], check=True)
-def build_intel_ixgbevf():
- """Build Intel IXGBEVF"""
- run(['./build-intel-ixgbevf.sh'], check=True)
+
+def build_realtek_r8152():
+ """Build Realtek r8152"""
+ run(['sudo', './build-realtek-r8152.py'], check=True)
def build_jool():
"""Build Jool"""
run(['echo y | ./build-jool.py'], check=True, shell=True)
+def build_ipt_netflow(commit_id, scm_url):
+ """Build ipt_NETFLOW"""
+ repo_dir = Path('ipt-netflow')
+ clone_or_update_repo(repo_dir, scm_url, commit_id)
+ run(['./build-ipt-netflow.sh'], check=True, shell=True)
def build_openvpn_dco(commit_id, scm_url):
"""Build OpenVPN DCO"""
diff --git a/scripts/package-build/linux-kernel/package.toml b/scripts/package-build/linux-kernel/package.toml
index 8b030da0..0bbd6785 100644
--- a/scripts/package-build/linux-kernel/package.toml
+++ b/scripts/package-build/linux-kernel/package.toml
@@ -22,7 +22,6 @@ commit_id = "1.13.0"
scm_url = "https://github.com/accel-ppp/accel-ppp.git"
build_cmd = "build_accel_ppp"
-
[[packages]]
name = "ovpn-dco"
commit_id = "v0.2.20231117"
@@ -35,7 +34,6 @@ commit_id = "475af0a"
scm_url = "https://github.com/maru-sama/rtsp-linux.git"
build_cmd = "build_nat_rtsp"
-
[[packages]]
name = "qat"
commit_id = ""
@@ -43,15 +41,21 @@ scm_url = ""
build_cmd = "build_intel_qat"
[[packages]]
+name = "igb"
+commit_id = "v5.18.7"
+scm_url = "https://github.com/intel/ethernet-linux-igb"
+build_cmd = "build_intel_igb"
+
+[[packages]]
name = "ixgbe"
-commit_id = ""
-scm_url = ""
+commit_id = "v6.0.5"
+scm_url = "https://github.com/intel/ethernet-linux-ixgbe"
build_cmd = "build_intel_ixgbe"
[[packages]]
name = "ixgbevf"
-commit_id = ""
-scm_url = ""
+commit_id = "v5.0.2"
+scm_url = "http://github.com/intel/ethernet-linux-ixgbevf"
build_cmd = "build_intel_ixgbevf"
[[packages]]
@@ -60,3 +64,20 @@ commit_id = ""
scm_url = ""
build_cmd = "build_jool"
+[[packages]]
+name = "mlnx"
+commit_id = ""
+scm_url = ""
+build_cmd = "build_mellanox_ofed"
+
+[[packages]]
+name = "realtek-r8152"
+commit_id = ""
+scm_url = ""
+build_cmd = "build_realtek_r8152"
+
+[[packages]]
+name = "ipt-netflow"
+commit_id = "0eb2092e93"
+scm_url = "https://github.com/aabc/ipt-netflow"
+build_cmd = "build_ipt_netflow"
diff --git a/scripts/package-build/linux-kernel/patches b/scripts/package-build/linux-kernel/patches
deleted file mode 120000
index fd016d35..00000000
--- a/scripts/package-build/linux-kernel/patches
+++ /dev/null
@@ -1 +0,0 @@
-../../../packages/linux-kernel/patches \ No newline at end of file
diff --git a/scripts/package-build/linux-kernel/patches/accel-ppp/0001-L2TP-Include-Calling-Number-to-Calling-Station-ID-RA.patch b/scripts/package-build/linux-kernel/patches/accel-ppp/0001-L2TP-Include-Calling-Number-to-Calling-Station-ID-RA.patch
new file mode 100644
index 00000000..0c3141a0
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/accel-ppp/0001-L2TP-Include-Calling-Number-to-Calling-Station-ID-RA.patch
@@ -0,0 +1,183 @@
+From 12778d1e9296b6dbf190a80dcf407b24f9821f95 Mon Sep 17 00:00:00 2001
+From: zsdc <taras@vyos.io>
+Date: Tue, 4 Apr 2023 11:15:26 +0300
+Subject: [PATCH] L2TP: Include Calling-Number to Calling-Station-ID RADIUS
+ attribute
+
+Patch authored by Alexander Serkin from
+https://phabricator.accel-ppp.org/T59
+---
+ accel-pppd/ctrl/l2tp/l2tp.c | 112 ++++++++++++++++++++++++++++++------
+ 1 file changed, 93 insertions(+), 19 deletions(-)
+
+diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
+index 027d710..c541c60 100644
+--- a/accel-pppd/ctrl/l2tp/l2tp.c
++++ b/accel-pppd/ctrl/l2tp/l2tp.c
+@@ -123,6 +123,11 @@ struct l2tp_sess_t
+ struct l2tp_conn_t *paren_conn;
+ uint16_t sid;
+ uint16_t peer_sid;
++/* We will keep l2tp attributes Calling-Number/Called-Number and their length while the session exists */
++ char *calling_num;
++ int calling_num_len;
++ char *called_num;
++ int called_num_len;
+
+ unsigned int ref_count;
+ int state1;
+@@ -979,6 +984,10 @@ static void __session_destroy(struct l2tp_sess_t *sess)
+ _free(sess->ctrl.calling_station_id);
+ if (sess->ctrl.called_station_id)
+ _free(sess->ctrl.called_station_id);
++ if (sess->calling_num)
++ _free(sess->calling_num);
++ if (sess->called_num)
++ _free(sess->called_num);
+
+ log_session(log_info2, sess, "session destroyed\n");
+
+@@ -1771,25 +1780,52 @@ static int l2tp_session_start_data_channel(struct l2tp_sess_t *sess)
+ sess->ctrl.max_mtu = conf_ppp_max_mtu;
+ sess->ctrl.mppe = conf_mppe;
+
+- sess->ctrl.calling_station_id = _malloc(17);
+- if (sess->ctrl.calling_station_id == NULL) {
+- log_session(log_error, sess,
+- "impossible to start data channel:"
+- " allocation of calling station ID failed\n");
+- goto err;
++ /* If l2tp calling number avp exists, we use it, otherwise we use lac ip */
++ if (sess->calling_num != NULL) {
++ sess->ctrl.calling_station_id = _malloc(sess->calling_num_len+1);
++ if (sess->ctrl.calling_station_id == NULL) {
++ log_session(log_error, sess,
++ "impossible to start data channel:"
++ " allocation of calling station ID failed\n");
++ goto err;
++ }else {
++ strcpy(sess->ctrl.calling_station_id, sess->calling_num);
++ }
++ } else {
++ sess->ctrl.calling_station_id = _malloc(17);
++ if (sess->ctrl.calling_station_id == NULL) {
++ log_session(log_error, sess,
++ "impossible to start data channel:"
++ " allocation of calling station ID failed\n");
++ goto err;
++ } else {
++ u_inet_ntoa(sess->paren_conn->peer_addr.sin_addr.s_addr,
++ sess->ctrl.calling_station_id);
++ }
+ }
+- u_inet_ntoa(sess->paren_conn->peer_addr.sin_addr.s_addr,
+- sess->ctrl.calling_station_id);
+-
+- sess->ctrl.called_station_id = _malloc(17);
+- if (sess->ctrl.called_station_id == NULL) {
+- log_session(log_error, sess,
+- "impossible to start data channel:"
+- " allocation of called station ID failed\n");
+- goto err;
++ /* If l2tp called number avp exists, we use it, otherwise we use my ip */
++ if (sess->called_num != NULL) {
++ sess->ctrl.called_station_id = _malloc(sess->called_num_len+1);
++ if (sess->ctrl.called_station_id == NULL) {
++ log_session(log_error, sess,
++ "impossible to start data channel:"
++ " allocation of called station ID failed\n");
++ goto err;
++ } else {
++ strcpy(sess->ctrl.called_station_id, sess->called_num);
++ }
++ } else {
++ sess->ctrl.called_station_id = _malloc(17);
++ if (sess->ctrl.called_station_id == NULL) {
++ log_session(log_error, sess,
++ "impossible to start data channel:"
++ " allocation of called station ID failed\n");
++ goto err;
++ } else {
++ u_inet_ntoa(sess->paren_conn->host_addr.sin_addr.s_addr,
++ sess->ctrl.called_station_id);
++ }
+ }
+- u_inet_ntoa(sess->paren_conn->host_addr.sin_addr.s_addr,
+- sess->ctrl.called_station_id);
+
+ if (conf_ip_pool) {
+ sess->ppp.ses.ipv4_pool_name = _strdup(conf_ip_pool);
+@@ -3295,6 +3331,10 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
+ uint16_t sid = 0;
+ uint16_t res = 0;
+ uint16_t err = 0;
++ uint8_t *calling[254] = {0};
++ uint8_t *called[254] = {0};
++ int n = 0;
++ int m = 0;
+
+ if (conn->state != STATE_ESTB && conn->lns_mode) {
+ log_tunnel(log_warn, conn, "discarding unexpected ICRQ\n");
+@@ -3332,7 +3372,17 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
+ case Call_Serial_Number:
+ case Bearer_Type:
+ case Calling_Number:
++ /* Save Calling-Number L2TP attribute locally */
++ if (attr->attr->id == Calling_Number) {
++ n = attr->length;
++ memcpy(calling,attr->val.octets,n);
++ }
+ case Called_Number:
++ /* Save Called-Number L2TP attribute locally */
++ if (attr->attr->id == Called_Number) {
++ m = attr->length;
++ memcpy(called,attr->val.octets,m);
++ }
+ case Sub_Address:
+ case Physical_Channel_ID:
+ break;
+@@ -3371,6 +3421,30 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
+ sess->peer_sid = peer_sid;
+ sid = sess->sid;
+
++ /* Allocate memory for Calling-Number if exists, and put it to l2tp_sess_t structure */
++ if (calling != NULL && n > 0) {
++ sess->calling_num = _malloc(n+1);
++ if (sess->calling_num == NULL) {
++ log_tunnel(log_warn, conn, "can't allocate memory for Calling Number attribute. Will use LAC IP instead\n");
++ }else{
++ memcpy(sess->calling_num, calling, n);
++ sess->calling_num[n] = '\0';
++ sess->calling_num_len = n;
++ }
++ }
++
++ /* Allocate memory for Called-Number if exists, and put it to l2tp_sess_t structure */
++ if (called != NULL && m > 1) {
++ sess->called_num = _malloc(m+1);
++ if (sess->called_num == NULL) {
++ log_tunnel(log_warn, conn, "can't allocate memory for Called Number attribute. Will use my IP instead\n");
++ } else {
++ memcpy(sess->called_num, called, m);
++ sess->called_num[m] = '\0';
++ sess->called_num_len = m;
++ }
++ }
++
+ if (unknown_attr) {
+ log_tunnel(log_error, conn, "impossible to handle ICRQ:"
+ " unknown mandatory attribute type %i,"
+@@ -3390,8 +3464,8 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
+ goto out_reject;
+ }
+
+- log_tunnel(log_info1, conn, "new session %hu-%hu created following"
+- " reception of ICRQ\n", sid, peer_sid);
++ log_tunnel(log_info1, conn, "new session %hu-%hu with calling num %s len %d, called num %s len %d created following"
++ " reception of ICRQ\n", sid, peer_sid, sess->calling_num, sess->calling_num_len, sess->called_num, sess->called_num_len);
+
+ return 0;
+
+--
+2.34.1
+
diff --git a/scripts/package-build/linux-kernel/patches/accel-ppp/0002-Radius-Dns-Server-IPv6-Address.patch b/scripts/package-build/linux-kernel/patches/accel-ppp/0002-Radius-Dns-Server-IPv6-Address.patch
new file mode 100644
index 00000000..a8991801
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/accel-ppp/0002-Radius-Dns-Server-IPv6-Address.patch
@@ -0,0 +1,195 @@
+From: Ben Hardill <ben@hardill.me.uk>
+Date: Tue, 13 Mar 2025 05:00:00 +0000
+Subject: [PATCH] PPPoE: IPv6 DNS from Radius - managing the DNS-Server-IPv6-Address attribute
+
+Patch authored by Ben Hardill from
+https://github.com/accel-ppp/accel-ppp/pull/69
+---
+diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
+index 70515133..507eae04 100644
+--- a/accel-pppd/include/ap_session.h
++++ b/accel-pppd/include/ap_session.h
+@@ -84,6 +84,7 @@ struct ap_session
+ struct ipv4db_item_t *ipv4;
+ struct ipv6db_item_t *ipv6;
+ struct ipv6db_prefix_t *ipv6_dp;
++ struct ipv6db_item_t *ipv6_dns;
+ char *ipv4_pool_name;
+ char *ipv6_pool_name;
+ char *dpv6_pool_name;
+diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
+index 158771b1..1ef48132 100644
+--- a/accel-pppd/ipv6/dhcpv6.c
++++ b/accel-pppd/ipv6/dhcpv6.c
+@@ -214,19 +214,41 @@ static void insert_status(struct dhcpv6_packet *pkt, struct dhcpv6_option *opt,
+ status->code = htons(code);
+ }
+
+-static void insert_oro(struct dhcpv6_packet *reply, struct dhcpv6_option *opt)
++static void insert_oro(struct dhcpv6_packet *reply, struct dhcpv6_option *opt, struct ap_session *ses)
+ {
+ struct dhcpv6_option *opt1;
+- int i, j;
++ int i = 0, j = 0, k = 0;
+ uint16_t *ptr;
+ struct in6_addr addr, *addr_ptr;
++ struct ipv6db_addr_t *dns;
+
+ for (i = ntohs(opt->hdr->len) / 2, ptr = (uint16_t *)opt->hdr->data; i; i--, ptr++) {
+ if (ntohs(*ptr) == D6_OPTION_DNS_SERVERS) {
+- if (conf_dns_count) {
+- opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, conf_dns_count * sizeof(addr));
+- for (j = 0, addr_ptr = (struct in6_addr *)opt1->hdr->data; j < conf_dns_count; j++, addr_ptr++)
+- memcpy(addr_ptr, conf_dns + j, sizeof(addr));
++ if (ses->ipv6_dns && !list_empty(&ses->ipv6_dns->addr_list)) {
++ list_for_each_entry(dns, &ses->ipv6_dns->addr_list, entry) {
++ j++;
++ }
++ if (j >= 3) {
++ j = 3;
++ }
++ opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, j * sizeof(addr));
++ addr_ptr = (struct in6_addr *)opt1->hdr->data;
++ list_for_each_entry(dns, &ses->ipv6_dns->addr_list, entry) {
++ if (k < j) {
++ memcpy(addr_ptr, &dns->addr, sizeof(addr));
++ k++;
++ addr_ptr++;
++ } else {
++ break;
++ }
++ }
++
++ } else {
++ if (conf_dns_count) {
++ opt1 = dhcpv6_option_alloc(reply, D6_OPTION_DNS_SERVERS, conf_dns_count * sizeof(addr));
++ for (j = 0, addr_ptr = (struct in6_addr *)opt1->hdr->data; j < conf_dns_count; j++, addr_ptr++)
++ memcpy(addr_ptr, conf_dns + j, sizeof(addr));
++ }
+ }
+ } else if (ntohs(*ptr) == D6_OPTION_DOMAIN_LIST) {
+ if (conf_dnssl_size) {
+@@ -434,7 +456,10 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
+
+ // Option Request
+ } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO) {
+- insert_oro(reply, opt);
++ if (ses->ipv6_dns &&!list_empty(&ses->ipv6_dns->addr_list)) {
++ log_ppp_info2("User specific IPv6 DNS entries\n");
++ }
++ insert_oro(reply, opt, ses);
+
+ } else if (ntohs(opt->hdr->code) == D6_OPTION_RAPID_COMMIT) {
+ if (req->hdr->type == D6_SOLICIT)
+@@ -594,7 +619,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
+ }
+ // Option Request
+ } else if (ntohs(opt->hdr->code) == D6_OPTION_ORO)
+- insert_oro(reply, opt);
++ insert_oro(reply, opt, ses);
+ }
+
+ opt1 = dhcpv6_option_alloc(reply, D6_OPTION_PREFERENCE, 1);
+diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c
+index 297e4d63..b3054274 100644
+--- a/accel-pppd/ipv6/nd.c
++++ b/accel-pppd/ipv6/nd.c
+@@ -174,7 +174,32 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ds
+ rinfo++;
+ }*/
+
+- if (conf_dns_count) {
++ if (ses->ipv6_dns && !list_empty(&ses->ipv6_dns->addr_list)) {
++ int i = 0, j = 0;
++ struct ipv6db_addr_t *dns;
++
++ list_for_each_entry(dns, &ses->ipv6_dns->addr_list, entry) {
++ i++;
++ }
++ if (i >= 3) {
++ i = 3;
++ }
++ rdnssinfo = (struct nd_opt_rdnss_info_local *)pinfo;
++ memset(rdnssinfo, 0, sizeof(*rdnssinfo));
++ rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION;
++ rdnssinfo->nd_opt_rdnssi_len = 1 + 2 * i;
++ rdnssinfo->nd_opt_rdnssi_lifetime = htonl(conf_rdnss_lifetime);
++ rdnss_addr = (struct in6_addr *)rdnssinfo->nd_opt_rdnssi;
++ list_for_each_entry(dns, &ses->ipv6_dns->addr_list, entry) {
++ if (j < i) {
++ memcpy(rdnss_addr, &dns->addr, sizeof(*rdnss_addr));
++ j++;
++ rdnss_addr++;
++ } else {
++ break;
++ }
++ }
++ } else if (conf_dns_count) {
+ rdnssinfo = (struct nd_opt_rdnss_info_local *)pinfo;
+ memset(rdnssinfo, 0, sizeof(*rdnssinfo));
+ rdnssinfo->nd_opt_rdnssi_type = ND_OPT_RDNSS_INFORMATION;
+diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
+index 786faa56..1379b0b2 100644
+--- a/accel-pppd/radius/radius.c
++++ b/accel-pppd/radius/radius.c
+@@ -403,6 +403,12 @@ int rad_proc_attrs(struct rad_req_t *req)
+ case Framed_IPv6_Route:
+ rad_add_framed_ipv6_route(attr->val.string, rpd);
+ break;
++ case DNS_Server_IPv6_Address:
++ a = _malloc(sizeof(*a));
++ memset(a, 0, sizeof(*a));
++ a->addr = attr->val.ipv6addr;
++ list_add_tail(&a->entry, &rpd->ipv6_dns.addr_list);
++ break;
+ }
+ }
+
+@@ -420,6 +426,9 @@ int rad_proc_attrs(struct rad_req_t *req)
+ if (!rpd->ses->ipv6_dp && !list_empty(&rpd->ipv6_dp.prefix_list))
+ rpd->ses->ipv6_dp = &rpd->ipv6_dp;
+
++ if (!rpd->ses->ipv6_dns && !list_empty(&rpd->ipv6_dns.addr_list))
++ rpd->ses->ipv6_dns = &rpd->ipv6_dns;
++
+ return res;
+ }
+
+@@ -584,10 +593,12 @@ static void ses_starting(struct ap_session *ses)
+ INIT_LIST_HEAD(&rpd->plugin_list);
+ INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list);
+ INIT_LIST_HEAD(&rpd->ipv6_dp.prefix_list);
++ INIT_LIST_HEAD(&rpd->ipv6_dns.addr_list);
+
+ rpd->ipv4_addr.owner = &ipdb;
+ rpd->ipv6_addr.owner = &ipdb;
+ rpd->ipv6_dp.owner = &ipdb;
++ rpd->ipv6_dns.owner = &ipdb;
+
+ list_add_tail(&rpd->pd.entry, &ses->pd_list);
+
+@@ -764,6 +775,12 @@ static void ses_finished(struct ap_session *ses)
+ _free(a);
+ }
+
++ while (!list_empty(&rpd->ipv6_dns.addr_list)) {
++ a = list_entry(rpd->ipv6_dns.addr_list.next, typeof(*a), entry);
++ list_del(&a->entry);
++ _free(a);
++ }
++
+ fr6 = rpd->fr6;
+ while (fr6) {
+ struct framed_ip6_route *next = fr6->next;
+diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
+index 988f154f..eaa5acb0 100644
+--- a/accel-pppd/radius/radius_p.h
++++ b/accel-pppd/radius/radius_p.h
+@@ -65,6 +65,7 @@ struct radius_pd_t {
+ struct ipv4db_item_t ipv4_addr;
+ struct ipv6db_item_t ipv6_addr;
+ struct ipv6db_prefix_t ipv6_dp;
++ struct ipv6db_item_t ipv6_dns;
+ int acct_interim_interval;
+ int acct_interim_jitter;
+
diff --git a/scripts/package-build/linux-kernel/patches/ixgbe/0001-ixgbe-always-enable-support-for-unsupported-SFP-modu.patch b/scripts/package-build/linux-kernel/patches/ixgbe/0001-ixgbe-always-enable-support-for-unsupported-SFP-modu.patch
new file mode 100644
index 00000000..3f2cbb4f
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/ixgbe/0001-ixgbe-always-enable-support-for-unsupported-SFP-modu.patch
@@ -0,0 +1,48 @@
+From a3ebb453f4a8c95fe3674d09646edb93946d450a Mon Sep 17 00:00:00 2001
+From: Christian Breunig <christian@breunig.cc>
+Date: Sat, 15 Feb 2025 09:17:10 +0100
+Subject: [PATCH] ixgbe: always enable support for unsupported SFP+ modules
+
+---
+ src/ixgbe_param.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/ixgbe_param.c b/src/ixgbe_param.c
+index bba03ae..3f29492 100644
+--- a/src/ixgbe_param.c
++++ b/src/ixgbe_param.c
+@@ -307,7 +307,7 @@ IXGBE_PARAM(LRO, "Large Receive Offload (0,1), default 0 = off");
+ * Default Value: 0
+ */
+ IXGBE_PARAM(allow_unsupported_sfp, "Allow unsupported and untested "
+- "SFP+ modules on 82599 based adapters, default 0 = Disable");
++ "SFP+ modules on 82599 based adapters, default 1 = Enable");
+
+ /* Enable/disable support for DMA coalescing
+ *
+@@ -1135,8 +1135,8 @@ void ixgbe_check_options(struct ixgbe_adapter *adapter)
+ struct ixgbe_option opt = {
+ .type = enable_option,
+ .name = "allow_unsupported_sfp",
+- .err = "defaulting to Disabled",
+- .def = OPTION_DISABLED
++ .err = "defaulting to Enabled",
++ .def = OPTION_ENABLED
+ };
+ #ifdef module_param_array
+ if (num_allow_unsupported_sfp > bd) {
+@@ -1152,7 +1152,11 @@ void ixgbe_check_options(struct ixgbe_adapter *adapter)
+ }
+ #ifdef module_param_array
+ } else {
++ if (opt.def == OPTION_ENABLED) {
++ adapter->hw.allow_unsupported_sfp = true;
++ } else {
+ adapter->hw.allow_unsupported_sfp = false;
++ }
+ }
+ #endif
+ }
+--
+2.39.5
+
diff --git a/scripts/package-build/linux-kernel/patches/ixgbe/0002-BACKPORT-linux-v6.9-PATCH-ixgbe-Add-1000BASE-BX-supp.patch b/scripts/package-build/linux-kernel/patches/ixgbe/0002-BACKPORT-linux-v6.9-PATCH-ixgbe-Add-1000BASE-BX-supp.patch
new file mode 100644
index 00000000..924c248b
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/ixgbe/0002-BACKPORT-linux-v6.9-PATCH-ixgbe-Add-1000BASE-BX-supp.patch
@@ -0,0 +1,259 @@
+From 0ef6088d0d93fcda7adee59fe675f96bcae36c13 Mon Sep 17 00:00:00 2001
+From: Christian Breunig <christian@breunig.cc>
+Date: Sat, 15 Feb 2025 09:17:35 +0100
+Subject: [PATCH] [BACKPORT linux v6.9] [PATCH] ixgbe: Add 1000BASE-BX support
+
+Added support for 1000BASE-BX, i.e. Gigabit Ethernet over single strand
+of single-mode fiber.
+The initialization of a 1000BASE-BX SFP is the same as 1000BASE-SX/LX
+with the only difference that the Bit Rate Nominal Value must be
+checked to make sure it is a Gigabit Ethernet transceiver, as described
+by the SFF-8472 specification.
+
+This was tested with the FS.com SFP-GE-BX 1310/1490nm 10km transceiver:
+$ ethtool -m eth4
+ Identifier : 0x03 (SFP)
+ Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID)
+ Connector : 0x07 (LC)
+ Transceiver codes : 0x00 0x00 0x00 0x40 0x00 0x00 0x00 0x00 0x00
+ Transceiver type : Ethernet: BASE-BX10
+ Encoding : 0x01 (8B/10B)
+ BR, Nominal : 1300MBd
+ Rate identifier : 0x00 (unspecified)
+ Length (SMF,km) : 10km
+ Length (SMF) : 10000m
+ Length (50um) : 0m
+ Length (62.5um) : 0m
+ Length (Copper) : 0m
+ Length (OM3) : 0m
+ Laser wavelength : 1310nm
+ Vendor name : FS
+ Vendor OUI : 64:9d:99
+ Vendor PN : SFP-GE-BX
+ Vendor rev :
+ Option values : 0x20 0x0a
+ Option : RX_LOS implemented
+ Option : TX_FAULT implemented
+ Option : Power level 3 requirement
+ BR margin, max : 0%
+ BR margin, min : 0%
+ Vendor SN : S2202359108
+ Date code : 220307
+ Optical diagnostics support : Yes
+ Laser bias current : 17.650 mA
+ Laser output power : 0.2132 mW / -6.71 dBm
+ Receiver signal average optical power : 0.2740 mW / -5.62 dBm
+ Module temperature : 47.30 degrees C / 117.13 degrees F
+ Module voltage : 3.2576 V
+ Alarm/warning flags implemented : Yes
+ Laser bias current high alarm : Off
+ Laser bias current low alarm : Off
+ Laser bias current high warning : Off
+ Laser bias current low warning : Off
+ Laser output power high alarm : Off
+ Laser output power low alarm : Off
+ Laser output power high warning : Off
+ Laser output power low warning : Off
+ Module temperature high alarm : Off
+ Module temperature low alarm : Off
+ Module temperature high warning : Off
+ Module temperature low warning : Off
+ Module voltage high alarm : Off
+ Module voltage low alarm : Off
+ Module voltage high warning : Off
+ Module voltage low warning : Off
+ Laser rx power high alarm : Off
+ Laser rx power low alarm : Off
+ Laser rx power high warning : Off
+ Laser rx power low warning : Off
+ Laser bias current high alarm threshold : 110.000 mA
+ Laser bias current low alarm threshold : 1.000 mA
+ Laser bias current high warning threshold : 100.000 mA
+ Laser bias current low warning threshold : 1.000 mA
+ Laser output power high alarm threshold : 0.7079 mW / -1.50 dBm
+ Laser output power low alarm threshold : 0.0891 mW / -10.50 dBm
+ Laser output power high warning threshold : 0.6310 mW / -2.00 dBm
+ Laser output power low warning threshold : 0.1000 mW / -10.00 dBm
+ Module temperature high alarm threshold : 90.00 degrees C / 194.00 degrees F
+ Module temperature low alarm threshold : -45.00 degrees C / -49.00 degrees F
+ Module temperature high warning threshold : 85.00 degrees C / 185.00 degrees F
+ Module temperature low warning threshold : -40.00 degrees C / -40.00 degrees F
+ Module voltage high alarm threshold : 3.7950 V
+ Module voltage low alarm threshold : 2.8050 V
+ Module voltage high warning threshold : 3.4650 V
+ Module voltage low warning threshold : 3.1350 V
+ Laser rx power high alarm threshold : 0.7079 mW / -1.50 dBm
+ Laser rx power low alarm threshold : 0.0028 mW / -25.53 dBm
+ Laser rx power high warning threshold : 0.6310 mW / -2.00 dBm
+ Laser rx power low warning threshold : 0.0032 mW / -24.95 dBm
+
+Signed-off-by: Ernesto Castellotti <ernesto@castellotti.net>
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Tested-by: Sunitha Mekala <sunithax.d.mekala@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Link: https://lore.kernel.org/r/20240301184806.2634508-3-anthony.l.nguyen@intel.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ src/ixgbe_82599.c | 4 +++-
+ src/ixgbe_ethtool.c | 4 ++++
+ src/ixgbe_phy.c | 33 +++++++++++++++++++++++++++++----
+ src/ixgbe_phy.h | 2 ++
+ src/ixgbe_type.h | 2 ++
+ 5 files changed, 40 insertions(+), 5 deletions(-)
+
+diff --git a/src/ixgbe_82599.c b/src/ixgbe_82599.c
+index c95fc4f..a5c74df 100644
+--- a/src/ixgbe_82599.c
++++ b/src/ixgbe_82599.c
+@@ -395,7 +395,9 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+- hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1) {
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = true;
+ goto out;
+diff --git a/src/ixgbe_ethtool.c b/src/ixgbe_ethtool.c
+index e983035..7dc9343 100644
+--- a/src/ixgbe_ethtool.c
++++ b/src/ixgbe_ethtool.c
+@@ -412,6 +412,8 @@ static int ixgbe_get_link_ksettings(struct net_device *netdev,
+ case ixgbe_sfp_type_1g_sx_core1:
+ case ixgbe_sfp_type_1g_lx_core0:
+ case ixgbe_sfp_type_1g_lx_core1:
++ case ixgbe_sfp_type_1g_bx_core0:
++ case ixgbe_sfp_type_1g_bx_core1:
+ ethtool_link_ksettings_add_link_mode(cmd, supported,
+ FIBRE);
+ ethtool_link_ksettings_add_link_mode(cmd, advertising,
+@@ -642,6 +644,8 @@ static int ixgbe_get_settings(struct net_device *netdev,
+ case ixgbe_sfp_type_1g_sx_core1:
+ case ixgbe_sfp_type_1g_lx_core0:
+ case ixgbe_sfp_type_1g_lx_core1:
++ case ixgbe_sfp_type_1g_bx_core0:
++ case ixgbe_sfp_type_1g_bx_core1:
+ ecmd->supported |= SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_FIBRE;
+ ecmd->port = PORT_FIBRE;
+diff --git a/src/ixgbe_phy.c b/src/ixgbe_phy.c
+index 3d99a88..3632234 100644
+--- a/src/ixgbe_phy.c
++++ b/src/ixgbe_phy.c
+@@ -1268,6 +1268,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+ u8 comp_codes_1g = 0;
+ u8 comp_codes_10g = 0;
+ u8 oui_bytes[3] = {0, 0, 0};
++ u8 bitrate_nominal = 0;
+ u8 cable_tech = 0;
+ u8 cable_spec = 0;
+ u16 enforce_sfp = 0;
+@@ -1311,6 +1312,12 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+ IXGBE_SFF_CABLE_TECHNOLOGY,
+ &cable_tech);
+
++ if (status != IXGBE_SUCCESS)
++ goto err_read_i2c_eeprom;
++
++ status = hw->phy.ops.read_i2c_eeprom(hw,
++ IXGBE_SFF_BITRATE_NOMINAL,
++ &bitrate_nominal);
+ if (status != IXGBE_SUCCESS)
+ goto err_read_i2c_eeprom;
+
+@@ -1393,6 +1400,18 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+ else
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_lx_core1;
++ /* Support only Ethernet 1000BASE-BX10, checking the Bit Rate
++ * Nominal Value as per SFF-8472 by convention 1.25 Gb/s should
++ * be rounded up to 0Dh (13 in units of 100 MBd) for 1000BASE-BX
++ */
++ } else if ((comp_codes_1g & IXGBE_SFF_BASEBX10_CAPABLE) &&
++ (bitrate_nominal == 0xD)) {
++ if (hw->bus.lan_id == 0)
++ hw->phy.sfp_type =
++ ixgbe_sfp_type_1g_bx_core0;
++ else
++ hw->phy.sfp_type =
++ ixgbe_sfp_type_1g_bx_core1;
+ } else {
+ hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+ }
+@@ -1483,7 +1502,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+- hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+ hw->phy.type = ixgbe_phy_sfp_unsupported;
+ status = IXGBE_ERR_SFP_NOT_SUPPORTED;
+ goto out;
+@@ -1502,7 +1523,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+- hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core0 ||
++ hw->phy.sfp_type == ixgbe_sfp_type_1g_bx_core1)) {
+ /* Make sure we're a supported PHY type */
+ if (hw->phy.type == ixgbe_phy_sfp_intel) {
+ status = IXGBE_SUCCESS;
+@@ -1821,12 +1844,14 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
+ if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+- sfp_type == ixgbe_sfp_type_1g_sx_core0)
++ sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
++ sfp_type == ixgbe_sfp_type_1g_bx_core0)
+ sfp_type = ixgbe_sfp_type_srlr_core0;
+ else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
+ sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+- sfp_type == ixgbe_sfp_type_1g_sx_core1)
++ sfp_type == ixgbe_sfp_type_1g_sx_core1 ||
++ sfp_type == ixgbe_sfp_type_1g_bx_core1)
+ sfp_type = ixgbe_sfp_type_srlr_core1;
+
+ /* Read offset to PHY init contents */
+diff --git a/src/ixgbe_phy.h b/src/ixgbe_phy.h
+index b6ddb2e..29c4645 100644
+--- a/src/ixgbe_phy.h
++++ b/src/ixgbe_phy.h
+@@ -18,6 +18,7 @@
+ #define IXGBE_SFF_1GBE_COMP_CODES 0x6
+ #define IXGBE_SFF_10GBE_COMP_CODES 0x3
+ #define IXGBE_SFF_CABLE_TECHNOLOGY 0x8
++#define IXGBE_SFF_BITRATE_NOMINAL 0xC
+ #define IXGBE_SFF_CABLE_SPEC_COMP 0x3C
+ #define IXGBE_SFF_SFF_8472_SWAP 0x5C
+ #define IXGBE_SFF_SFF_8472_COMP 0x5E
+@@ -40,6 +41,7 @@
+ #define IXGBE_SFF_1GBASESX_CAPABLE 0x1
+ #define IXGBE_SFF_1GBASELX_CAPABLE 0x2
+ #define IXGBE_SFF_1GBASET_CAPABLE 0x8
++#define IXGBE_SFF_BASEBX10_CAPABLE 0x64
+ #define IXGBE_SFF_10GBASESR_CAPABLE 0x10
+ #define IXGBE_SFF_10GBASELR_CAPABLE 0x20
+ #define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8
+diff --git a/src/ixgbe_type.h b/src/ixgbe_type.h
+index 1700599..403687c 100644
+--- a/src/ixgbe_type.h
++++ b/src/ixgbe_type.h
+@@ -3722,6 +3722,8 @@ enum ixgbe_sfp_type {
+ ixgbe_sfp_type_1g_sx_core1 = 12,
+ ixgbe_sfp_type_1g_lx_core0 = 13,
+ ixgbe_sfp_type_1g_lx_core1 = 14,
++ ixgbe_sfp_type_1g_bx_core0 = 15,
++ ixgbe_sfp_type_1g_bx_core1 = 16,
+ ixgbe_sfp_type_not_present = 0xFFFE,
+ ixgbe_sfp_type_unknown = 0xFFFF
+ };
+--
+2.39.5
+
diff --git a/scripts/package-build/linux-kernel/patches/kernel/0001-linkstate-ip-device-attribute.patch b/scripts/package-build/linux-kernel/patches/kernel/0001-linkstate-ip-device-attribute.patch
new file mode 100644
index 00000000..7bd0b04b
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/kernel/0001-linkstate-ip-device-attribute.patch
@@ -0,0 +1,158 @@
+From 81d38c4a32e059ad7835f7dc254e7627642afbe9 Mon Sep 17 00:00:00 2001
+From: Stephen Hemminger <stephen@networkplumber.org>
+Date: Mon, 29 Apr 2013 18:50:15 -0700
+Subject: [PATCH] VyOS: Add linkstate IP device attribute
+
+Backport of earlier Vyatta patch.
+
+(cherry picked from commit 7c5a851086686be14ae937c80d6cee34814dbefc)
+---
+ Documentation/networking/ip-sysctl.rst | 11 +++++++++++
+ include/linux/inetdevice.h | 1 +
+ include/linux/ipv6.h | 1 +
+ include/uapi/linux/ip.h | 1 +
+ include/uapi/linux/ipv6.h | 1 +
+ net/ipv4/devinet.c | 1 +
+ net/ipv6/addrconf.c | 8 ++++++++
+ net/ipv6/route.c | 10 ++++++++++
+ 8 files changed, 34 insertions(+)
+
+diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
+index a66054d0763a..53440098fa98 100644
+--- a/Documentation/networking/ip-sysctl.rst
++++ b/Documentation/networking/ip-sysctl.rst
+@@ -1734,6 +1734,17 @@ src_valid_mark - BOOLEAN
+
+ Default value is 0.
+
++link_filter - INTEGER
++ 0 - Allow packets to be received for the address on this interface
++ even if interface is disabled or no carrier.
++ 1 - Ignore packets received if interface associated with the incoming
++ address is down.
++ 2 - Ignore packets received if interface associated with the incoming
++ address is down or has no carrier.
++
++ Default value is 0. Note that some distributions enable it
++ in startup scripts.
++
+ arp_filter - BOOLEAN
+ - 1 - Allows you to have multiple network interfaces on the same
+ subnet, and have the ARPs for each interface be answered
+diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
+index ddb27fc0ee8c..8ee3191d9558 100644
+--- a/include/linux/inetdevice.h
++++ b/include/linux/inetdevice.h
+@@ -137,6 +137,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
+ #define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
+ #define IN_DEV_ARP_EVICT_NOCARRIER(in_dev) IN_DEV_ANDCONF((in_dev), \
+ ARP_EVICT_NOCARRIER)
++#define IN_DEV_LINKFILTER(in_dev) IN_DEV_MAXCONF((in_dev), LINKFILTER)
+
+ struct in_ifaddr {
+ struct hlist_node hash;
+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
+index af8a771a053c..ece8ac89d317 100644
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -84,6 +84,7 @@ struct ipv6_devconf {
+ __u8 ndisc_evict_nocarrier;
+
+ struct ctl_table_header *sysctl_header;
++ __s32 link_filter;
+ };
+
+ struct ipv6_params {
+diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
+index 283dec7e3645..8067941a635e 100644
+--- a/include/uapi/linux/ip.h
++++ b/include/uapi/linux/ip.h
+@@ -173,6 +173,7 @@ enum
+ IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
+ IPV4_DEVCONF_BC_FORWARDING,
+ IPV4_DEVCONF_ARP_EVICT_NOCARRIER,
++ IPV4_DEVCONF_LINKFILTER,
+ __IPV4_DEVCONF_MAX
+ };
+
+diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
+index cf592d7b630f..e8915701aa73 100644
+--- a/include/uapi/linux/ipv6.h
++++ b/include/uapi/linux/ipv6.h
+@@ -199,6 +199,7 @@ enum {
+ DEVCONF_NDISC_EVICT_NOCARRIER,
+ DEVCONF_ACCEPT_UNTRACKED_NA,
+ DEVCONF_ACCEPT_RA_MIN_LFT,
++ DEVCONF_LINK_FILTER,
+ DEVCONF_MAX
+ };
+
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index c33b1ecc591e..7576d51cd16d 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -2609,6 +2609,7 @@ static struct devinet_sysctl_table {
+ "route_localnet"),
+ DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
+ "drop_unicast_in_l2_multicast"),
++ DEVINET_SYSCTL_RW_ENTRY(LINKFILTER, "link_filter"),
+ },
+ };
+
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 8360939acf85..b13832a08d28 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -5674,6 +5674,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
+ array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
+ array[DEVCONF_ACCEPT_UNTRACKED_NA] = cnf->accept_untracked_na;
+ array[DEVCONF_ACCEPT_RA_MIN_LFT] = cnf->accept_ra_min_lft;
++ array[DEVCONF_LINK_FILTER] = cnf->link_filter;
+ }
+
+ static inline size_t inet6_ifla6_size(void)
+@@ -7103,6 +7104,13 @@ static const struct ctl_table addrconf_sysctl[] = {
+ .extra1 = (void *)SYSCTL_ZERO,
+ .extra2 = (void *)SYSCTL_ONE,
+ },
++ {
++ .procname = "link_filter",
++ .data = &ipv6_devconf.link_filter,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec,
++ },
+ {
+ .procname = "ioam6_id",
+ .data = &ipv6_devconf.ioam6_id,
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 5715d54f3d0b..e88971b512ba 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -682,6 +682,14 @@ static inline void rt6_probe(struct fib6_nh *fib6_nh)
+ }
+ #endif
+
++static inline int rt6_link_filter(const struct fib6_nh *nh)
++{
++ const struct net_device *dev = nh->fib_nh_dev;
++ int linkf = __in6_dev_get(dev)->cnf.link_filter;
++ return (linkf && !netif_running(dev))
++ || (linkf > 1 && !netif_carrier_ok(dev));
++}
++
+ /*
+ * Default Router Selection (RFC 2461 6.3.6)
+ */
+@@ -723,6 +731,8 @@ static int rt6_score_route(const struct fib6_nh *nh, u32 fib6_flags, int oif,
+
+ if (!m && (strict & RT6_LOOKUP_F_IFACE))
+ return RT6_NUD_FAIL_HARD;
++ if (rt6_link_filter(nh))
++ return -1;
+ #ifdef CONFIG_IPV6_ROUTER_PREF
+ m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(fib6_flags)) << 2;
+ #endif
+--
+2.39.5
+
diff --git a/scripts/package-build/linux-kernel/patches/kernel/0002-inotify-support-for-stackable-filesystems.patch b/scripts/package-build/linux-kernel/patches/kernel/0002-inotify-support-for-stackable-filesystems.patch
new file mode 100644
index 00000000..b19a8d25
--- /dev/null
+++ b/scripts/package-build/linux-kernel/patches/kernel/0002-inotify-support-for-stackable-filesystems.patch
@@ -0,0 +1,298 @@
+From 1d625d2f745b61a718ce52cd1729f467c17defa6 Mon Sep 17 00:00:00 2001
+From: Alex Harpin <development@landsofshadow.co.uk>
+Date: Wed, 31 Dec 2014 10:33:38 +0000
+Subject: [PATCH] VyOS: add inotify support for stackable filesystems
+ (overlayfs)
+
+As it stands at the moment, overlayfs doesn't have full support for
+inotify, and as such anything that relies on inotify currently has
+issues. The simplest method of demonstrating this is to tail a file
+(so tail -f /var/log/messages) and see that it doesn't follow changes
+in that file. This has been reported in a number of places, including
+Bug #882147 in Ubuntu. This patch is based on the version proposed by
+Li Jianguo in response to this bug, adding support for inotify in
+stackable filesystems.
+
+This commit provides a complete fix for the workaround implemented
+for bug #303, and will allow that commit to be reverted.
+
+Bug #425 http://bugzilla.vyos.net/show_bug.cgi?id=425
+
+(cherry picked from commit a93f1128bc83b5a6628da242e71c18ef05e81ea2)
+---
+ fs/notify/inotify/Kconfig | 9 +++
+ fs/notify/inotify/inotify_user.c | 114 ++++++++++++++++++++++++++++++-
+ fs/overlayfs/super.c | 27 ++++++--
+ include/linux/inotify.h | 28 ++++++++
+ 4 files changed, 172 insertions(+), 6 deletions(-)
+
+diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
+index 1cc8be25df7e..bc4acd1a6ea4 100644
+--- a/fs/notify/inotify/Kconfig
++++ b/fs/notify/inotify/Kconfig
+@@ -15,3 +15,12 @@ config INOTIFY_USER
+ For more information, see <file:Documentation/filesystems/inotify.rst>
+
+ If unsure, say Y.
++
++config INOTIFY_STACKFS
++ bool "Inotify support for stackable filesystem"
++ select INOTIFY_USER
++ default y
++ help
++ Say Y here to enable inotify support for stackable filesystem.
++
++ If unsure, say N.
+diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
+index 1c4bfdab008d..cf567cc33679 100644
+--- a/fs/notify/inotify/inotify_user.c
++++ b/fs/notify/inotify/inotify_user.c
+@@ -15,6 +15,7 @@
+
+ #include <linux/file.h>
+ #include <linux/fs.h> /* struct inode */
++#include <linux/mount.h>
+ #include <linux/fsnotify_backend.h>
+ #include <linux/idr.h>
+ #include <linux/init.h> /* fs_initcall */
+@@ -97,6 +98,93 @@ static void __init inotify_sysctls_init(void)
+ #define inotify_sysctls_init() do { } while (0)
+ #endif /* CONFIG_SYSCTL */
+
++#ifdef CONFIG_INOTIFY_STACKFS
++
++static DEFINE_RWLOCK(inotify_fs_lock);
++static LIST_HEAD(inotify_fs_list);
++
++static inline struct file_system_type* peek_fs_type(struct path *path)
++{
++ return path->mnt->mnt_sb->s_type;
++}
++
++static struct inotify_stackfs* inotify_get_stackfs(struct path *path)
++{
++ struct file_system_type *fs;
++ struct inotify_stackfs *fse, *ret = NULL;
++
++ fs = peek_fs_type(path);
++
++ read_lock(&inotify_fs_lock);
++ list_for_each_entry(fse, &inotify_fs_list, list) {
++ if (fse->fs_type == fs) {
++ ret = fse;
++ break;
++ }
++ }
++ read_unlock(&inotify_fs_lock);
++
++ return ret;
++}
++
++static inline void inotify_put_stackfs(struct inotify_stackfs *fs)
++{
++}
++
++int inotify_register_stackfs(struct inotify_stackfs *fs)
++{
++ int ret = 0;
++ struct inotify_stackfs *fse;
++
++ BUG_ON(IS_ERR_OR_NULL(fs->fs_type));
++ BUG_ON(IS_ERR_OR_NULL(fs->func));
++
++ INIT_LIST_HEAD(&fs->list);
++
++ write_lock(&inotify_fs_lock);
++ list_for_each_entry(fse, &inotify_fs_list, list) {
++ if (fse->fs_type == fs->fs_type) {
++ write_unlock(&inotify_fs_lock);
++ ret = -EBUSY;
++ goto out;
++ }
++ }
++ list_add_tail(&fs->list, &inotify_fs_list);
++ write_unlock(&inotify_fs_lock);
++
++out:
++ return ret;
++}
++EXPORT_SYMBOL_GPL(inotify_register_stackfs);
++
++void inotify_unregister_stackfs(struct inotify_stackfs *fs)
++{
++ struct inotify_stackfs *fse, *n;
++
++ write_lock(&inotify_fs_lock);
++ list_for_each_entry_safe(fse, n, &inotify_fs_list, list) {
++ if (fse == fs) {
++ list_del(&fse->list);
++ break;
++ }
++ }
++ write_unlock(&inotify_fs_lock);
++}
++EXPORT_SYMBOL_GPL(inotify_unregister_stackfs);
++
++#else
++
++static inline struct inotify_stackfs* inotify_get_stackfs(struct path *path)
++{
++ return NULL;
++}
++
++static inline void inotify_put_stackfs(struct inotify_stackfs *fs)
++{
++}
++
++#endif /* CONFIG_INOTIFY_STACKFS */
++
+ static inline __u32 inotify_arg_to_mask(struct inode *inode, u32 arg)
+ {
+ __u32 mask;
+@@ -370,8 +458,8 @@ static const struct file_operations inotify_fops = {
+ /*
+ * find_inode - resolve a user-given path to a specific inode
+ */
+-static int inotify_find_inode(const char __user *dirname, struct path *path,
+- unsigned int flags, __u64 mask)
++static inline int __inotify_find_inode(const char __user *dirname, struct path *path,
++ unsigned int flags, __u64 mask)
+ {
+ int error;
+
+@@ -392,6 +480,28 @@ static int inotify_find_inode(const char __user *dirname, struct path *path,
+ return error;
+ }
+
++static int inotify_find_inode(const char __user *dirname, struct path *path,
++ unsigned int flags, __u64 mask)
++{
++ int ret;
++ struct path tpath;
++ struct inotify_stackfs *fse;
++
++ ret = __inotify_find_inode(dirname, &tpath, flags, mask);
++ if (ret)
++ return ret;
++ fse = inotify_get_stackfs(&tpath);
++ if (fse == NULL) {
++ *path = tpath;
++ return 0;
++ }
++ ret = fse->func(path, &tpath);
++ inotify_put_stackfs(fse);
++ path_put(&tpath);
++
++ return ret;
++}
++
+ static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
+ struct inotify_inode_mark *i_mark)
+ {
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 2c056d737c27..2cb1f0024e70 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -15,6 +15,7 @@
+ #include <linux/seq_file.h>
+ #include <linux/posix_acl_xattr.h>
+ #include <linux/exportfs.h>
++#include <linux/inotify.h>
+ #include <linux/file.h>
+ #include <linux/fs_context.h>
+ #include <linux/fs_parser.h>
+@@ -1528,6 +1529,18 @@ static void ovl_inode_init_once(void *foo)
+ inode_init_once(&oi->vfs_inode);
+ }
+
++static int ovl_inotify_path(struct path *dst, struct path *src)
++{
++ ovl_path_real(src->dentry, dst);
++ path_get(dst);
++ return 0;
++}
++
++static struct inotify_stackfs ovl_inotify = {
++ .fs_type = &ovl_fs_type,
++ .func = ovl_inotify_path,
++};
++
+ static int __init ovl_init(void)
+ {
+ int err;
+@@ -1543,18 +1556,24 @@ static int __init ovl_init(void)
+ err = ovl_aio_request_cache_init();
+ if (!err) {
+ err = register_filesystem(&ovl_fs_type);
+- if (!err)
+- return 0;
++ if (err)
++ goto err;
++ err = inotify_register_stackfs(&ovl_inotify);
++ if (err)
++ goto err;
++ return 0;
+
+- ovl_aio_request_cache_destroy();
+ }
++err:
+ kmem_cache_destroy(ovl_inode_cachep);
+-
++ unregister_filesystem(&ovl_fs_type);
++ ovl_aio_request_cache_destroy();
+ return err;
+ }
+
+ static void __exit ovl_exit(void)
+ {
++ inotify_unregister_stackfs(&ovl_inotify);
+ unregister_filesystem(&ovl_fs_type);
+
+ /*
+diff --git a/include/linux/inotify.h b/include/linux/inotify.h
+index 8d20caa1b268..c126e2f93a73 100644
+--- a/include/linux/inotify.h
++++ b/include/linux/inotify.h
+@@ -8,6 +8,8 @@
+ #define _LINUX_INOTIFY_H
+
+ #include <uapi/linux/inotify.h>
++#include <linux/list.h>
++#include <linux/fs.h>
+
+ #define ALL_INOTIFY_BITS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+ IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+@@ -17,4 +19,30 @@
+ IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_MASK_ADD | \
+ IN_MASK_CREATE | IN_ISDIR | IN_ONESHOT)
+
++typedef int (*inotify_path_proc)(struct path *dst, struct path *src);
++
++struct inotify_stackfs {
++ struct list_head list; /* entry in inotify_fs_list */
++ struct file_system_type *fs_type; /* registed file_system_type */
++ inotify_path_proc func; /* registed callback function */
++};
++
++#ifdef CONFIG_INOTIFY_STACKFS
++
++extern int inotify_register_stackfs(struct inotify_stackfs *fs);
++extern void inotify_unregister_stackfs(struct inotify_stackfs *fs);
++
++#else
++
++static inline int inotify_register_stackfs(struct inotify_stackfs *fs)
++{
++ return 0;
++}
++
++static inline void inotify_unregister_stackfs(struct inotify_stackfs *fs)
++{
++}
++
++#endif /* CONFIG_INOTIFY_STACKFS */
++
+ #endif /* _LINUX_INOTIFY_H */
+--
+2.39.2
+
diff --git a/scripts/package-build/linux-kernel/sign-modules.sh b/scripts/package-build/linux-kernel/sign-modules.sh
new file mode 100755
index 00000000..cfb368eb
--- /dev/null
+++ b/scripts/package-build/linux-kernel/sign-modules.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+BASE_DIR=$(dirname $0)
+MODULE_DIR=$1
+. ${BASE_DIR}/kernel-vars
+
+SIGN_FILE="${KERNEL_DIR}/scripts/sign-file"
+
+if [ -f ${EPHEMERAL_KEY} ] && [ -f ${EPHEMERAL_CERT} ]; then
+ find ${MODULE_DIR} -type f -name \*.ko | while read MODULE; do
+ echo "I: Signing ${MODULE} ..."
+ ${SIGN_FILE} sha512 ${EPHEMERAL_KEY} ${EPHEMERAL_CERT} ${MODULE}
+ done
+fi
+
diff --git a/scripts/package-build/ndppd/.gitignore b/scripts/package-build/ndppd/.gitignore
index 2b71e9fb..4983088e 100644
--- a/scripts/package-build/ndppd/.gitignore
+++ b/scripts/package-build/ndppd/.gitignore
@@ -1,7 +1 @@
-ndppd/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/ndppd/
diff --git a/scripts/package-build/ndppd/patches/0001-skip-route-table-if-there-is-no-auto-rule.patch b/scripts/package-build/ndppd/patches/ndppd/0001-skip-route-table-if-there-is-no-auto-rule.patch
index df6d2e5c..df6d2e5c 100644
--- a/scripts/package-build/ndppd/patches/0001-skip-route-table-if-there-is-no-auto-rule.patch
+++ b/scripts/package-build/ndppd/patches/ndppd/0001-skip-route-table-if-there-is-no-auto-rule.patch
diff --git a/scripts/package-build/ndppd/patches/0002-set-vyos-version.patch b/scripts/package-build/ndppd/patches/ndppd/0002-set-vyos-version.patch
index 3fef87c4..3fef87c4 100644
--- a/scripts/package-build/ndppd/patches/0002-set-vyos-version.patch
+++ b/scripts/package-build/ndppd/patches/ndppd/0002-set-vyos-version.patch
diff --git a/scripts/package-build/net-snmp/.gitignore b/scripts/package-build/net-snmp/.gitignore
index 67811e63..ce30b515 100644
--- a/scripts/package-build/net-snmp/.gitignore
+++ b/scripts/package-build/net-snmp/.gitignore
@@ -1,6 +1 @@
-net-snmp/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/net-snmp/
diff --git a/scripts/package-build/net-snmp/patches/add-linux-6.7-compatibility-parsing.patch b/scripts/package-build/net-snmp/patches/net-snmp/add-linux-6.7-compatibility-parsing.patch
index b6dcd77a..b6dcd77a 100644
--- a/scripts/package-build/net-snmp/patches/add-linux-6.7-compatibility-parsing.patch
+++ b/scripts/package-build/net-snmp/patches/net-snmp/add-linux-6.7-compatibility-parsing.patch
diff --git a/scripts/package-build/netfilter/.gitignore b/scripts/package-build/netfilter/.gitignore
index 9bf39f82..ea401bf3 100644
--- a/scripts/package-build/netfilter/.gitignore
+++ b/scripts/package-build/netfilter/.gitignore
@@ -1,8 +1,2 @@
/pkg-libnftnl/
/pkg-nftables/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
diff --git a/scripts/package-build/netfilter/build.py b/scripts/package-build/netfilter/build.py
index 9737b7d3..3c76af73 100755..120000
--- a/scripts/package-build/netfilter/build.py
+++ b/scripts/package-build/netfilter/build.py
@@ -1,189 +1 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2024 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import glob
-import shutil
-import toml
-import os
-
-from argparse import ArgumentParser
-from pathlib import Path
-from subprocess import run, CalledProcessError
-
-
-def ensure_dependencies(dependencies: list) -> None:
- """Ensure Debian build dependencies are met"""
- if not dependencies:
- print("I: No additional dependencies to install")
- return
-
- print("I: Ensure Debian build dependencies are met")
- run(['sudo', 'apt-get', 'update'], check=True)
- run(['sudo', 'apt-get', 'install', '-y'] + dependencies, check=True)
-
-
-def apply_patches(repo_dir: Path, patch_dir: Path, package_name: str) -> None:
- """Apply patches from the patch directory to the repository"""
- package_patch_dir = patch_dir / package_name
- if package_patch_dir.exists() and package_patch_dir.is_dir():
- patches = list(package_patch_dir.glob('*'))
- else:
- print(f"I: No patch directory found for {package_name} in {patch_dir}")
- return
-
- # Filter out directories from patches list
- patches = [patch for patch in patches if patch.is_file()]
-
- if not patches:
- print(f"I: No patches found in {package_patch_dir}")
- return
-
- debian_patches_dir = repo_dir / 'debian/patches'
- debian_patches_dir.mkdir(parents=True, exist_ok=True)
-
- series_file = debian_patches_dir / 'series'
- with series_file.open('a') as series:
- for patch in patches:
- patch_dest = debian_patches_dir / patch.name
- try:
- # Ensure the patch file exists before copying
- if patch.exists():
- shutil.copy(patch, patch_dest)
- series.write(patch.name + '\n')
- print(f"I: Applied patch: {patch.name}")
- else:
- print(f"W: Patch file {patch} not found, skipping")
- except FileNotFoundError:
- print(f"W: Patch file {patch} not found, skipping")
-
-
-def prepare_package(repo_dir: Path, install_data: str) -> None:
- """Prepare a package"""
- if not install_data:
- print("I: No install data provided, skipping package preparation")
- return
-
- try:
- install_file = repo_dir / 'debian/install'
- install_file.parent.mkdir(parents=True, exist_ok=True)
- install_file.write_text(install_data)
- print("I: Prepared package")
- except Exception as e:
- print(f"Failed to prepare package: {e}")
- raise
-
-
-def build_package(package: dict, dependencies: list, patch_dir: Path) -> None:
- """Build a package from the repository
-
- Args:
- package (dict): Package information
- dependencies (list): List of additional dependencies
- patch_dir (Path): Directory containing patches
- """
- repo_name = package['name']
- repo_dir = Path(repo_name)
-
- try:
- # Clone the repository if it does not exist
- if not repo_dir.exists():
- run(['git', 'clone', package['scm_url'], str(repo_dir)], check=True)
-
- # Check out the specific commit
- run(['git', 'checkout', package['commit_id']], cwd=repo_dir, check=True)
-
- # Ensure dependencies
- ensure_dependencies(dependencies)
-
- # Apply patches if any
- apply_patches(repo_dir, patch_dir, repo_name)
-
- # Prepare the package if required
- if package.get('prepare_package', False):
- prepare_package(repo_dir, package.get('install_data', ''))
-
- # Build dependency package and install it
- if (repo_dir / 'debian/control').exists():
- try:
- run('sudo mk-build-deps --install --tool "apt-get --yes --no-install-recommends"', cwd=repo_dir, check=True, shell=True)
- run('sudo dpkg -i *build-deps*.deb', cwd=repo_dir, check=True, shell=True)
- except CalledProcessError as e:
- print(f"Failed to build package {repo_name}: {e}")
-
- # Build the package, check if we have build_cmd in the package.toml
- build_cmd = package.get('build_cmd', 'dpkg-buildpackage -uc -us -tc -b')
- run(build_cmd, cwd=repo_dir, check=True, shell=True)
-
- except CalledProcessError as e:
- print(f"Failed to build package {repo_name}: {e}")
- finally:
- # Clean up repository directory
- # shutil.rmtree(repo_dir, ignore_errors=True)
- pass
-
-
-def cleanup_build_deps(repo_dir: Path) -> None:
- """Clean up build dependency packages"""
- try:
- if repo_dir.exists():
- for file in glob.glob(str(repo_dir / '*build-deps*.deb')):
- os.remove(file)
- print("Cleaned up build dependency packages")
- except Exception as e:
- print(f"Error cleaning up build dependencies: {e}")
-
-
-def copy_packages(repo_dir: Path) -> None:
- """Copy generated .deb packages to the parent directory"""
- try:
- deb_files = glob.glob(str(repo_dir / '*.deb'))
- for deb_file in deb_files:
- shutil.copy(deb_file, repo_dir.parent)
- print(f'I: copy generated "{deb_file}" package')
- except Exception as e:
- print(f"Error copying packages: {e}")
-
-
-if __name__ == '__main__':
- # Prepare argument parser
- arg_parser = ArgumentParser()
- arg_parser.add_argument('--config',
- default='package.toml',
- help='Path to the package configuration file')
- arg_parser.add_argument('--patch-dir',
- default='patches',
- help='Path to the directory containing patches')
- args = arg_parser.parse_args()
-
- # Load package configuration
- with open(args.config, 'r') as file:
- config = toml.load(file)
-
- packages = config['packages']
- patch_dir = Path(args.patch_dir)
-
- for package in packages:
- dependencies = package.get('dependencies', {}).get('packages', [])
-
- # Build the package
- build_package(package, dependencies, patch_dir)
-
- # Clean up build dependency packages after build
- cleanup_build_deps(Path(package['name']))
-
- # Copy generated .deb packages to parent directory
- copy_packages(Path(package['name']))
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/node_exporter/.gitignore b/scripts/package-build/node_exporter/.gitignore
new file mode 100644
index 00000000..25d6ffd3
--- /dev/null
+++ b/scripts/package-build/node_exporter/.gitignore
@@ -0,0 +1 @@
+node_exporter/
diff --git a/scripts/package-build/node_exporter/build.py b/scripts/package-build/node_exporter/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/node_exporter/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/node_exporter/package.toml b/scripts/package-build/node_exporter/package.toml
new file mode 100644
index 00000000..4540bc82
--- /dev/null
+++ b/scripts/package-build/node_exporter/package.toml
@@ -0,0 +1,21 @@
+[[packages]]
+name = "node_exporter"
+commit_id = "v1.9.1"
+scm_url = "https://github.com/prometheus/node_exporter"
+
+build_cmd = """
+
+# Create the install directory
+mkdir -p debian/usr/sbin
+make build
+
+# Move the node_exporter binary to the install directory
+mv node_exporter debian/usr/sbin
+
+# Build the Debian package
+fpm --input-type dir --output-type deb --name node-exporter \
+ --version $(git describe --tags --always | cut -c2-) --deb-compression gz \
+ --maintainer "VyOS Package Maintainers <maintainers@vyos.net>" \
+ --description "Prometheus exporter for machine metrics" \
+ --license Apache-2.0 -C debian --package ..
+"""
diff --git a/scripts/package-build/opennhrp/package.toml b/scripts/package-build/opennhrp/package.toml
deleted file mode 100644
index d647c072..00000000
--- a/scripts/package-build/opennhrp/package.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[[packages]]
-name = "opennhrp"
-commit_id = "613277f"
-scm_url = "https://git.code.sf.net/p/opennhrp/code"
-
-build_cmd = """
-make clean
-make
-
-install --directory debian/etc debian/usr/sbin
-install --mode 0644 etc/racoon-ph1dead.sh debian/etc
-install --mode 0644 etc/racoon-ph1down.sh debian/etc
-install --strip --mode 0755 nhrp/opennhrp debian/usr/sbin
-install --strip --mode 0755 nhrp/opennhrpctl debian/usr/sbin
-
-fpm --input-type dir --output-type deb --name opennhrp \
- --version $(git describe --always | cut -c2-) --deb-compression gz \
- --maintainer "VyOS Package Maintainers <maintainers@vyos.net>" \
- --description "NBMA Next Hop Resolution Protocol daemon" \
- --license "MIT" -C debian --package ..
-"""
diff --git a/scripts/package-build/openvpn-otp/.gitignore b/scripts/package-build/openvpn-otp/.gitignore
index 7f89da2b..90268525 100644
--- a/scripts/package-build/openvpn-otp/.gitignore
+++ b/scripts/package-build/openvpn-otp/.gitignore
@@ -1,6 +1 @@
-openvpn-otp/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/openvpn-otp/
diff --git a/scripts/package-build/openvpn-otp/package.toml b/scripts/package-build/openvpn-otp/package.toml
index 72209ad1..bdbc6d9d 100644
--- a/scripts/package-build/openvpn-otp/package.toml
+++ b/scripts/package-build/openvpn-otp/package.toml
@@ -1,6 +1,6 @@
[[packages]]
name = "openvpn-otp"
-commit_id = "master"
+commit_id = "9781ff1"
scm_url = "https://github.com/evgeny-gridasov/openvpn-otp"
# build_cmd = "cd ..; ./build-openvpn-otp.sh"
diff --git a/scripts/package-build/owamp/.gitignore b/scripts/package-build/owamp/.gitignore
index 4a97524e..c6efde63 100644
--- a/scripts/package-build/owamp/.gitignore
+++ b/scripts/package-build/owamp/.gitignore
@@ -1,6 +1 @@
-owamp/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/owamp/
diff --git a/scripts/package-build/pam_tacplus/.gitignore b/scripts/package-build/pam_tacplus/.gitignore
deleted file mode 100644
index 04e8d4e9..00000000
--- a/scripts/package-build/pam_tacplus/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-pam_tacplus/
-pam_tacplus-debian/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
diff --git a/scripts/package-build/pam_tacplus/package.toml b/scripts/package-build/pam_tacplus/package.toml
deleted file mode 100644
index 79b28544..00000000
--- a/scripts/package-build/pam_tacplus/package.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[[packages]]
-name = "pam_tacplus-debian"
-commit_id = "50c6fd7"
-scm_url = "https://github.com/kravietz/pam_tacplus-debian"
-build_cmd = "/bin/true"
-
-[[packages]]
-name = "pam_tacplus"
-#commit_id = "4f91b0d" # This commit cannot build the package
-commit_id = "b839c44"
-scm_url = "https://github.com/kravietz/pam_tacplus"
-
-#build_cmd = "sudo mk-build-deps --install --tool 'apt-get --yes --no-install-recommends'; cd ..; ./build.sh"
-build_cmd = """
-cp -a ../pam_tacplus-debian debian
-rm -f debian/compat
-sudo mk-build-deps --install --tool 'apt-get --yes --no-install-recommends'
-dpkg-buildpackage -uc -us -tc -b -d
-"""
diff --git a/scripts/package-build/pmacct/.gitignore b/scripts/package-build/pmacct/.gitignore
index 7007417a..65042174 100644
--- a/scripts/package-build/pmacct/.gitignore
+++ b/scripts/package-build/pmacct/.gitignore
@@ -1,6 +1 @@
-pmacct/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/pmacct/
diff --git a/scripts/package-build/pmacct/patches/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch b/scripts/package-build/pmacct/patches/pmacct/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch
index cb5f7399..cb5f7399 100644
--- a/scripts/package-build/pmacct/patches/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch
+++ b/scripts/package-build/pmacct/patches/pmacct/0001-fix-pmacctd-SEGV-when-ICMP-ICMPv6-traffic-was-proces.patch
diff --git a/scripts/package-build/podman/.gitignore b/scripts/package-build/podman/.gitignore
index 22c40b0e..dfba60a6 100644
--- a/scripts/package-build/podman/.gitignore
+++ b/scripts/package-build/podman/.gitignore
@@ -1,7 +1 @@
-podman/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/podman/
diff --git a/scripts/package-build/podman/package.toml b/scripts/package-build/podman/package.toml
index 952af518..707f3d7e 100644
--- a/scripts/package-build/podman/package.toml
+++ b/scripts/package-build/podman/package.toml
@@ -20,7 +20,7 @@ fpm --input-type dir --output-type deb --name podman \
--license "Apache License 2.0" -C podman-v$VERSION --package ..
"""
-[packages.dependencies]
+[dependencies]
packages = [
"libseccomp-dev",
"libgpgme-dev"
diff --git a/scripts/package-build/pyhumps/.gitignore b/scripts/package-build/pyhumps/.gitignore
index 6a90d1c9..27979294 100644
--- a/scripts/package-build/pyhumps/.gitignore
+++ b/scripts/package-build/pyhumps/.gitignore
@@ -1,7 +1 @@
-humps/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-
+/humps/
diff --git a/scripts/package-build/radvd/.gitignore b/scripts/package-build/radvd/.gitignore
index 9c37832b..b3761965 100644
--- a/scripts/package-build/radvd/.gitignore
+++ b/scripts/package-build/radvd/.gitignore
@@ -1,6 +1 @@
-radvd/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/radvd/
diff --git a/scripts/package-build/radvd/package.toml b/scripts/package-build/radvd/package.toml
index e44afa18..83b9936b 100644
--- a/scripts/package-build/radvd/package.toml
+++ b/scripts/package-build/radvd/package.toml
@@ -1,6 +1,6 @@
[[packages]]
name = "radvd"
-commit_id = "f2de4764559"
+commit_id = "v2.20"
scm_url = "https://github.com/radvd-project/radvd"
#build_cmd = "cd ..; ./build.sh"
diff --git a/scripts/package-build/strongswan/.gitignore b/scripts/package-build/strongswan/.gitignore
index ec612740..e4c36e8f 100644
--- a/scripts/package-build/strongswan/.gitignore
+++ b/scripts/package-build/strongswan/.gitignore
@@ -1,6 +1 @@
-strongswan/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/strongswan/
diff --git a/scripts/package-build/strongswan/build-vici.sh b/scripts/package-build/strongswan/build-vici.sh
index 5ad0ee80..75b180f0 100755
--- a/scripts/package-build/strongswan/build-vici.sh
+++ b/scripts/package-build/strongswan/build-vici.sh
@@ -4,7 +4,7 @@ set -e
SRC="strongswan/src/libcharon/plugins/vici/python"
if [ ! -d ${SRC} ]; then
- echo "Source directory does not exists, please 'git clone'"
+ echo "Source directory does not exist, please 'git clone'"
exit 1
fi
@@ -28,30 +28,31 @@ Depends: \${misc:Depends}, \${python3:Depends}
Description: Native Python interface for strongSwan's VICI protocol
EOF
-
# Create rules file
-echo "I: create $SRC/rules"
+echo "I: create $SRC/debian/rules"
cat <<EOF > debian/rules
#!/usr/bin/make -f
%:
dh \$@ --with python3
EOF
-# Make the rules file executable
chmod +x debian/rules
echo '10' > debian/compat
+# Add the 'install' file to copy the vici package to the correct directory
+echo "I: create $SRC/debian/install"
+cat <<EOF > debian/install
+vici /usr/lib/python3/dist-packages/
+EOF
+
# Copy changelog
cp ../../../../../debian/changelog debian/
-
-ls -la
-pwd
-
-
+# Build the package
echo "I: Build Debian Package"
dpkg-buildpackage -uc -us -tc -b -d
+# Copy the resulting .deb packages
echo "I: copy packages"
-cp ../*.deb ../../../../../../
+cp ../*.deb ../../../../../../
diff --git a/scripts/package-build/strongswan/package.toml b/scripts/package-build/strongswan/package.toml
index 8cedd4ac..a5722062 100644
--- a/scripts/package-build/strongswan/package.toml
+++ b/scripts/package-build/strongswan/package.toml
@@ -13,7 +13,7 @@ dpkg-buildpackage -uc -us -tc -b -d
cd ..; ./build-vici.sh
"""
-[packages.dependencies]
+[dependencies]
packages = [
"bison",
"bzip2",
diff --git a/scripts/package-build/strongswan/patches/0001-charon-add-optional-source-and-remote-overrides-for-.patch b/scripts/package-build/strongswan/patches/strongswan/0001-charon-add-optional-source-and-remote-overrides-for-.patch
index ceb47350..ceb47350 100644
--- a/scripts/package-build/strongswan/patches/0001-charon-add-optional-source-and-remote-overrides-for-.patch
+++ b/scripts/package-build/strongswan/patches/strongswan/0001-charon-add-optional-source-and-remote-overrides-for-.patch
diff --git a/scripts/package-build/strongswan/patches/0002-vici-send-certificates-for-ike-sa-events.patch b/scripts/package-build/strongswan/patches/strongswan/0002-vici-send-certificates-for-ike-sa-events.patch
index 13e657e9..13e657e9 100644
--- a/scripts/package-build/strongswan/patches/0002-vici-send-certificates-for-ike-sa-events.patch
+++ b/scripts/package-build/strongswan/patches/strongswan/0002-vici-send-certificates-for-ike-sa-events.patch
diff --git a/scripts/package-build/strongswan/patches/0003-vici-add-support-for-individual-sa-state-changes.patch b/scripts/package-build/strongswan/patches/strongswan/0003-vici-add-support-for-individual-sa-state-changes.patch
index 45aadc72..45aadc72 100644
--- a/scripts/package-build/strongswan/patches/0003-vici-add-support-for-individual-sa-state-changes.patch
+++ b/scripts/package-build/strongswan/patches/strongswan/0003-vici-add-support-for-individual-sa-state-changes.patch
diff --git a/scripts/package-build/strongswan/patches/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch b/scripts/package-build/strongswan/patches/strongswan/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch
index 57a622e8..57a622e8 100644
--- a/scripts/package-build/strongswan/patches/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch
+++ b/scripts/package-build/strongswan/patches/strongswan/0004-VyOS-disable-options-enabled-by-Debian-that-are-unus.patch
diff --git a/scripts/package-build/tacacs/.gitignore b/scripts/package-build/tacacs/.gitignore
new file mode 100644
index 00000000..3579fc4d
--- /dev/null
+++ b/scripts/package-build/tacacs/.gitignore
@@ -0,0 +1,3 @@
+/libnss-tacplus/
+/libpam-tacplus/
+/libtacplus-map/
diff --git a/scripts/package-build/tacacs/build.py b/scripts/package-build/tacacs/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/tacacs/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/tacacs/package.toml b/scripts/package-build/tacacs/package.toml
new file mode 100644
index 00000000..fde9df6e
--- /dev/null
+++ b/scripts/package-build/tacacs/package.toml
@@ -0,0 +1,24 @@
+[[packages]]
+name = "libtacplus-map"
+commit_id = "master"
+scm_url = "https://github.com/vyos/libtacplus-map.git"
+build_cmd = "dpkg-buildpackage -us -uc -tc -b"
+
+[[packages]]
+name = "libpam-tacplus"
+commit_id = "master"
+scm_url = "https://github.com/vyos/libpam-tacplus.git"
+build_cmd = "sudo dpkg -i ../libtacplus-map*.deb; dpkg-buildpackage -us -uc -tc -b"
+
+[[packages]]
+name = "libnss-tacplus"
+commit_id = "master"
+scm_url = "https://github.com/vyos/libnss-tacplus.git"
+build_cmd = "sudo dpkg -i ../libtac*.deb ../libpam-tacplus*.deb; dpkg-buildpackage -us -uc -tc -b"
+
+[dependencies]
+packages = [
+ "libpam-dev",
+ "autoconf-archive",
+ "libaudit-dev"
+]
diff --git a/scripts/package-build/telegraf/.gitignore b/scripts/package-build/telegraf/.gitignore
index bf2fcf43..f634da68 100644
--- a/scripts/package-build/telegraf/.gitignore
+++ b/scripts/package-build/telegraf/.gitignore
@@ -1,6 +1 @@
-telegraf/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
+/telegraf/
diff --git a/scripts/package-build/vpp/.gitignore b/scripts/package-build/vpp/.gitignore
new file mode 100644
index 00000000..38768675
--- /dev/null
+++ b/scripts/package-build/vpp/.gitignore
@@ -0,0 +1,2 @@
+/vpp/
+/vyos-vpp-patches/
diff --git a/scripts/package-build/vpp/build.py b/scripts/package-build/vpp/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/vpp/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/vpp/package.toml b/scripts/package-build/vpp/package.toml
new file mode 100644
index 00000000..1104e184
--- /dev/null
+++ b/scripts/package-build/vpp/package.toml
@@ -0,0 +1,35 @@
+[[packages]]
+name = "vyos-vpp-patches"
+commit_id = "current"
+scm_url = "https://github.com/vyos/vyos-vpp-patches"
+build_cmd = "/bin/true"
+apply_patches = false
+
+[[packages]]
+name = "vpp"
+commit_id = "stable/2410"
+scm_url = "https://github.com/FDio/vpp"
+# Skip apply patches by build.py as we use them in build_cmd
+apply_patches = false
+
+pre_build_hook = """
+mkdir -p ../patches/vpp/
+rsync -av ../vyos-vpp-patches/patches/vpp/ ../patches/vpp/
+"""
+
+build_cmd = """
+# Patches for vpp should applied here
+for patch in ../patches/vpp/*.patch; do
+ echo "I: build_cmd applying patch $patch..."
+ git -c user.email=maintainers@vyos.net -c user.name=vyos am "$patch" || { echo "Failed to apply patch $patch"; exit 1; }
+done
+
+make UNATTENDED=yes install-dep
+make pkg-deb
+cp build-root/*.deb ../
+"""
+
+[dependencies]
+packages = [
+ "llvm"
+]
diff --git a/scripts/package-build/vyos-1x/.gitignore b/scripts/package-build/vyos-1x/.gitignore
new file mode 100644
index 00000000..990c6351
--- /dev/null
+++ b/scripts/package-build/vyos-1x/.gitignore
@@ -0,0 +1,2 @@
+/vyos-1x/
+/vyos-vpp/
diff --git a/scripts/package-build/vyos-1x/build.py b/scripts/package-build/vyos-1x/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/vyos-1x/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/vyos-1x/package.toml b/scripts/package-build/vyos-1x/package.toml
new file mode 100644
index 00000000..6dcbadb3
--- /dev/null
+++ b/scripts/package-build/vyos-1x/package.toml
@@ -0,0 +1,11 @@
+[[packages]]
+name = "vyos-vpp"
+commit_id = "current"
+scm_url = "https://github.com/vyos/vyos-vpp.git"
+build_cmd = "/bin/true"
+
+[[packages]]
+name = "vyos-1x"
+commit_id = "current"
+scm_url = "https://github.com/vyos/vyos-1x.git"
+build_cmd = "rsync -av --exclude='.git' --exclude='.github' --exclude='README*' --exclude='LICENSE' --exclude='*.md' ../vyos-vpp/ ./; dpkg-buildpackage -us -uc -F"
diff --git a/scripts/package-build/waagent/.gitignore b/scripts/package-build/waagent/.gitignore
index 80401271..a91839ef 100644
--- a/scripts/package-build/waagent/.gitignore
+++ b/scripts/package-build/waagent/.gitignore
@@ -1,8 +1 @@
-waagent/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-*.tar.gz
-*.tar.xz
+/waagent/
diff --git a/scripts/package-build/waagent/package.toml b/scripts/package-build/waagent/package.toml
index d7343a7a..1a382baa 100644
--- a/scripts/package-build/waagent/package.toml
+++ b/scripts/package-build/waagent/package.toml
@@ -3,5 +3,5 @@ name = "waagent"
commit_id = "debian/2.9.1.1-2"
scm_url = "https://salsa.debian.org/cloud-team/waagent.git"
-[packages.dependencies]
+[dependencies]
packages = ["dpkg-source-gitarchive"]
diff --git a/scripts/package-build/wide-dhcpv6/.gitignore b/scripts/package-build/wide-dhcpv6/.gitignore
index 990f3c6c..b7f6e063 100644
--- a/scripts/package-build/wide-dhcpv6/.gitignore
+++ b/scripts/package-build/wide-dhcpv6/.gitignore
@@ -1,7 +1 @@
-wide-dhcpv6/
-*.buildinfo
-*.build
-*.changes
-*.deb
-*.dsc
-*.udeb
+/wide-dhcpv6/
diff --git a/scripts/package-build/wide-dhcpv6/patches/0023-dhcpc6-support-per-interface-client-DUIDs.patch b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0023-dhcpc6-support-per-interface-client-DUIDs.patch
index c1e71f0c..c1e71f0c 100644
--- a/scripts/package-build/wide-dhcpv6/patches/0023-dhcpc6-support-per-interface-client-DUIDs.patch
+++ b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0023-dhcpc6-support-per-interface-client-DUIDs.patch
diff --git a/scripts/package-build/wide-dhcpv6/patches/0024-bind-to-single-socket.patch b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0024-bind-to-single-socket.patch
index b5751325..b5751325 100644
--- a/scripts/package-build/wide-dhcpv6/patches/0024-bind-to-single-socket.patch
+++ b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0024-bind-to-single-socket.patch
diff --git a/scripts/package-build/wide-dhcpv6/patches/0025-option-to-prevent-ia-release.patch b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0025-option-to-prevent-ia-release.patch
index 32c15814..32c15814 100644
--- a/scripts/package-build/wide-dhcpv6/patches/0025-option-to-prevent-ia-release.patch
+++ b/scripts/package-build/wide-dhcpv6/patches/wide-dhcpv6/0025-option-to-prevent-ia-release.patch
diff --git a/scripts/package-build/xen-guest-agent/.gitignore b/scripts/package-build/xen-guest-agent/.gitignore
new file mode 100644
index 00000000..d34885ab
--- /dev/null
+++ b/scripts/package-build/xen-guest-agent/.gitignore
@@ -0,0 +1 @@
+/xen-guest-agent/
diff --git a/scripts/package-build/xen-guest-agent/build.py b/scripts/package-build/xen-guest-agent/build.py
new file mode 120000
index 00000000..3c76af73
--- /dev/null
+++ b/scripts/package-build/xen-guest-agent/build.py
@@ -0,0 +1 @@
+../build.py \ No newline at end of file
diff --git a/scripts/package-build/xen-guest-agent/package.toml b/scripts/package-build/xen-guest-agent/package.toml
new file mode 100644
index 00000000..213425df
--- /dev/null
+++ b/scripts/package-build/xen-guest-agent/package.toml
@@ -0,0 +1,34 @@
+[[packages]]
+name = "xen-guest-agent"
+commit_id = "0.4.0"
+scm_url = "https://gitlab.com/xen-project/xen-guest-agent"
+
+
+build_cmd = """
+# changelog
+cat <<EOF > debian/changelog
+xen-guest-agent (0.4.0) UNRELEASED; urgency=medium
+
+ * Upstream package
+
+ -- VyOS Maintainers <maintainers@vyos.io> Thu, 26 Sep 2024 12:35:47 +0000
+
+EOF
+
+# Apply the patch to modify the debian/rules file
+sed -i 's|../xen-guest-agent-$(UPSTREAM_VERSION)-linux-$(DEB_TARGET_GNU_CPU)|target/release/xen-guest-agent|' debian/rules
+
+sudo apt-get -y install --no-install-recommends libclang-dev libxen-dev
+# Install rust
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --default-toolchain stable --profile default --no-modify-path
+
+# Set PATH for Cargo
+export PATH="$HOME/.cargo/bin:$PATH"
+rustup update
+cd xen-guest-agent
+cargo update
+
+# Build deb
+cargo build -F static --profile release
+dpkg-buildpackage -b -us -uc
+"""