Add ngx_http_ipng_stats_module: per-VIP, per-device traffic counters

Full implementation of the nginx dynamic module with:
- SO_BINDTODEVICE-based per-interface traffic attribution
- Per-worker lock-free counters flushed to shared memory
- Prometheus text and JSON scrape endpoint at configurable location
- UDP-only global logtail (ipng_stats_logtail) for fire-and-forget
  access log streaming
- $ipng_source_tag nginx variable for use in log_format/map
- Histogram buckets, EWMA rate gauges, zone meta-metrics
- Debian packaging (libnginx-mod-http-ipng-stats)
- Robot Framework end-to-end tests via containerlab
- SPDX Apache-2.0 headers on all source files
This commit is contained in:
2026-04-16 17:36:42 +02:00
parent c05bcf6aa6
commit 5a7e2f77f1
25 changed files with 4016 additions and 102 deletions

12
debian/changelog vendored Normal file
View File

@@ -0,0 +1,12 @@
nginx-ipng-stats-plugin (0.1.0-1) unstable; urgency=medium
* Initial release.
- ngx_http_ipng_stats_module: per-VIP, per-device HTTP traffic
counters, attributed via SO_BINDTODEVICE on per-interface
listening sockets, exposed as Prometheus text and JSON from a
single scrape endpoint.
- Debian package libnginx-mod-http-ipng-stats builds against the
target release's nginx-dev headers with --with-compat and loads
into stock upstream nginx without recompiling nginx itself.
-- Pim van Pelt <pim@ipng.ch> Thu, 16 Apr 2026 00:00:00 +0000

38
debian/control vendored Normal file
View File

@@ -0,0 +1,38 @@
# SPDX-License-Identifier: Apache-2.0
Source: nginx-ipng-stats-plugin
Section: httpd
Priority: optional
Maintainer: Pim van Pelt <pim@ipng.ch>
Build-Depends:
debhelper-compat (= 13),
nginx-dev,
libpcre2-dev,
zlib1g-dev,
libssl-dev
Standards-Version: 4.6.2
Homepage: https://git.ipng.ch/ipng/nginx-ipng-stats-plugin
Rules-Requires-Root: no
Package: libnginx-mod-http-ipng-stats
Architecture: any
Depends:
${misc:Depends},
${shlibs:Depends},
nginx (>= 1.26~)
Description: nginx dynamic module for per-VIP, per-device traffic counters
This package ships ngx_http_ipng_stats_module as a dynamic module
loadable into stock upstream nginx on Debian. The module records
per-VIP HTTP request counters, status code distribution, bytes in
and out, and request-duration histograms, and attributes each
request to the interface it arrived on. Counters are exposed as
Prometheus text and JSON from a single scrape endpoint.
.
Attribution is done by the Linux kernel's TCP socket lookup, using
SO_BINDTODEVICE on per-interface listening sockets. The module adds
device= and ipng_source_tag= parameters to the nginx listen
directive; the kernel routes each incoming connection to the
correct listener by ingress interface.
.
Typical use cases include GRE tunnel fleets, VLAN trunks, or any
deployment where traffic arrives on distinct interfaces and
per-interface observability is needed.

28
debian/copyright vendored Normal file
View File

@@ -0,0 +1,28 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: nginx-ipng-stats-plugin
Upstream-Contact: Pim van Pelt <pim@ipng.ch>
Source: https://git.ipng.ch/ipng/nginx-ipng-stats-plugin
Files: *
Copyright: 2026 Pim van Pelt <pim@ipng.ch>
License: Apache-2.0
Files: debian/*
Copyright: 2026 Pim van Pelt <pim@ipng.ch>
License: Apache-2.0
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License version 2.0
can be found in `/usr/share/common-licenses/Apache-2.0'.

42
debian/libnginx-mod-http-ipng-stats.postinst vendored Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# postinst for libnginx-mod-http-ipng-stats
set -e
AVAIL=/etc/nginx/modules-available/50-mod-http-ipng-stats.conf
ENABLED=/etc/nginx/modules-enabled/50-mod-http-ipng-stats.conf
case "$1" in
configure)
# Enable the module by symlinking it into modules-enabled.
if [ ! -L "$ENABLED" ] && [ -f "$AVAIL" ]; then
ln -s "$AVAIL" "$ENABLED"
fi
# Sanity-check the resulting config. If nginx -t fails, back
# out the symlink so the operator isn't left with an nginx
# that cannot start.
if ! nginx -t > /dev/null 2>&1; then
echo "warning: nginx -t failed after enabling" \
"libnginx-mod-http-ipng-stats; disabling the module." >&2
rm -f "$ENABLED"
nginx -t >&2 || true
echo "warning: nginx-ipng-stats-plugin has been installed" \
"but is NOT enabled; fix the configuration error" \
"and re-enable with:" >&2
echo " sudo ln -s $AVAIL $ENABLED && sudo nginx -s reload" >&2
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

26
debian/libnginx-mod-http-ipng-stats.prerm vendored Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# prerm for libnginx-mod-http-ipng-stats
set -e
ENABLED=/etc/nginx/modules-enabled/50-mod-http-ipng-stats.conf
case "$1" in
remove|upgrade|deconfigure)
if [ -L "$ENABLED" ]; then
rm -f "$ENABLED"
fi
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

2
debian/mod-http-ipng-stats.conf vendored Normal file
View File

@@ -0,0 +1,2 @@
# SPDX-License-Identifier: Apache-2.0
load_module modules/ngx_http_ipng_stats_module.so;

39
debian/rules vendored Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/make -f
# SPDX-License-Identifier: Apache-2.0
# debian/rules for nginx-ipng-stats-plugin
#
# The actual module build is driven by the top-level Makefile, which
# copies /usr/share/nginx/src (from nginx-dev) into a writable
# build/nginx-src/ and runs the out-of-tree --add-dynamic-module dance
# against it. debian/rules just delegates to `make build` and installs
# the resulting .so into the package tree.
export DH_VERBOSE = 1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
MODULE_NAME := ngx_http_ipng_stats_module
PKG := libnginx-mod-http-ipng-stats
%:
dh $@
override_dh_auto_configure:
# No-op: configure happens inside `make build`.
override_dh_auto_build:
$(MAKE) build
override_dh_auto_install:
install -D -m 0644 \
$(CURDIR)/build/$(MODULE_NAME).so \
$(CURDIR)/debian/$(PKG)/usr/lib/nginx/modules/$(MODULE_NAME).so
install -D -m 0644 \
$(CURDIR)/debian/mod-http-ipng-stats.conf \
$(CURDIR)/debian/$(PKG)/etc/nginx/modules-available/50-mod-http-ipng-stats.conf
override_dh_auto_clean:
# Preserve build/ across clean so dpkg-buildpackage doesn't force
# a full rebuild of the fetched nginx source tree every time. The
# top-level `make clean` will flush it when the user really wants
# a fresh start.
dh_auto_clean

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)