Hi Lorenzo,

Thanks for your patience!

On Mon, Nov 24, 2025 at 03:17:06PM +0100, Lorenzo wrote:
> Control: tags -1 +moreinfo
> 
> On Sun, 16 Nov 2025 14:32:41 +0000 Andrew Bower <[email protected]> wrote:
> > Hi Lorenzo,
> > 
> > On Mon, Oct 20, 2025 at 05:53:20PM +0200, Lorenzo wrote:
> > > Let me know how it works if you have the chance to test it with
> > > gerbera or xl2tpd.
> > 
> > This is just a courtesy response to apologise for being slow to
> > evaluate and reply. I have some thoughts on this but need to dedicate
> > some attention to it without getting distracted!
> > 
> > In some ways there are no easy answers because no one, with any
> > supervision system, seems to have really perfectly solved this
> > problem!
> 
> Ok, let's put this on hold for a while.
> I'm attaching here the last version of the git patch for reference.

I am uncomfortable with this script as it seems heavy and non-generic
for the purposes required.

I did wonder, considering how it is going to be used, if, going back to
a runit service, it might as well listen on the netlink socket
continuously and let the 'check' script do the work of interpreting
current state, using a combination of rtmon(8) and ip-monitor(8).
However, I tried prototyping that solution a while ago and one problem
was that you couldn't get a dump of one of the needed tables (can't
remember if it was 'link' or 'address') at start of day to avoid a
possible race. There may have been other potential issues, too.

Another approach might be to supply hook scripts for the known network
configuration managers that raise a common flag file under /run
somewhere - this is cruder than what I was trying to achieve with only
depending on the minimum service level but it's probably what most
systemd services do anyway.

Yet another approach, going back to the facilities (we really should
have another bug for that, shouldn't we? My latest idea for that was
under #1121617, addressing your preference for a process not a shell
include) idea would be that each of the services that implement a
network facility could install their own hook script and their own check
script would check the flag raised by that. We'd need one to cover
ifupdown of course, although we'd still want the actual config done in
stage 1 I think?

Some specific review comments on the script below:

> From: Lorenzo Puliti <[email protected]>
> Date: Wed, 15 Oct 2025 15:24:07 +0200
> Subject: [PATCH] add a netcheck utility
> 
> add a netcheck utility to test for network status: it takes up to
> two parameters (scope= and family=); allowed values are
> scope=global|link|host; family=inet|inet6
> by default 'ip' is used, with a fallback on ifconfig; wireless is
> still a TODO; not tested with ip, requires an additional tool
> (iwconfig) with ifconfig.
> 
> this should help to unblock the following MRs:
>  https://salsa.debian.org/debian/runit-services/-/merge_requests/4
>  https://salsa.debian.org/debian/runit-services/-/merge_requests/9
> 
> Closes: #1117993
> ---
>  debian/control                |  2 +-
>  debian/extra/netcheck         | 82 +++++++++++++++++++++++++++++++++++
>  debian/runit-services.install |  1 +
>  3 files changed, 84 insertions(+), 1 deletion(-)
>  create mode 100755 debian/extra/netcheck
> 
> diff --git a/debian/control b/debian/control
> index c046842..d5db784 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -17,7 +17,7 @@ Breaks:
>   elogind (<< 255.4.1-1~),
>   xchpst (<< 0.6.0-1~),
>   sane-utils (<< 1.4.0~),
> -Recommends: runit-run | runit-init, libcap2-bin,
> +Recommends: runit-run | runit-init, libcap2-bin, iproute2 | net-tools,
>  Provides: mini-httpd-run
>  Suggests: socklog, xchpst
>  Description: UNIX init scheme with service supervision (services)
> diff --git a/debian/extra/netcheck b/debian/extra/netcheck
> new file mode 100755
> index 0000000..1f202d5
> --- /dev/null
> +++ b/debian/extra/netcheck
> @@ -0,0 +1,82 @@
> +#!/bin/sh
> +
> +# see #1117993
> +
> +err() { >&2 printf '%s\n\n' "$*"; exit 1; }
> +fatal() { err "${0##*/}: fatal: $*"; }
> +usage() { err "Usage: ${0##*/} [scope=<scope>] [family=<family>]"; }
> +#scope=[host|link|global]  ; family=[inet|inet6] 
> +#default: scope>=link; family=inet or inet6  #link?
> +
> +family=''; scope='link'; #defaults
> +
> +while [ $# -gt 0 ]; do
> +     case $1 in
> +                scope=*)
> +                scope="${1##*=}"
> +                [ "$scope" = 'host' ] || [ "$scope" = 'link' ] || \
> +                 [ "$scope" = 'global' ] || usage
> +                 #[ "$scope" = 'site' ] || not supported
> +             shift
> +                ;;
> +                family=*)
> +                family="${1##*=}"
> +                [ "$family" = 'inet' ] || [ "$family" = 'inet6' ] || usage

Why constrain the names and not just let them match or not naturally?

> +             shift
> +                ;;
> +                *)
> +             usage
> +                ;;
> +        esac
> +done
> +
> +[ ! -x /usr/sbin/ip ] && [ ! -x /usr/sbin/ifconfig ] && exit 111
> +fam=
> +if [ -n "$family" ]; then
> +     fam="-f $family"
> +fi
> +
> +for i in $(seq 1 14); do
> +     if [ -x /usr/sbin/ip ]; then
> +             for interf in $(ip addr | grep -Po '^\d+:\s+\K[^:]+') ; do

I wonder if it would be nicer to scan /proc/net/dev or something to pick
up interface names.

> +                     ip --oneline link show "$interf" | grep -q 'LOWER_UP' 
> || continue

Why do we need to check link up and does this do the right thing for
logical interfaces that might have non-obvious states?

I think that for the applications which really do depend on network
readiness, usually it's just to be able to bind to the right addresses
and interfaces, rather than being able to pass traffic, in order to
start up, although that may not be true for all, of course. In my
examples only binding was necessary.

> +                     #ip --oneline link show "$interf" | grep -q ' state UP' 
> || continue   --> loopback is ' state UNKNOWN'
> +                     case $scope in #global=0, link=253, host=254;
> +                             global) # ok=0
> +                             ip -oneline $fam -Numeric addr show "$interf" | 
> grep -Eq ' scope 0' && exit 0
> +                             ;;
> +                             link) #ok=253,0; rule out 255 and 254
> +                             ip -oneline $fam -Numeric addr show "$interf" | 
> grep -Evq ' scope 25[45]' && exit 0
> +                             ;;
> +                             host) #ok= 0, 253, 254; rule out 255
> +                             ip -oneline $fam -Numeric addr show "$interf" | 
> grep -Evq ' scope 255' && exit 0
> +                             ;;

I don't like the number of times we are invoking iproute2. As well as
starting the tool, each time we are setting up a netlink socket and
scanning a lot of the same information, discarding a different amount
each time. I would prefer to capture once and then process. (This script
might be cleaner written as perl, which is essential anyway, as that is
way better for processing inputs.)

> +                     esac
> +             done
> +     elif [ -x /usr/sbin/ifconfig ]; then

A shame to need to have the second method but I accept you want a
non-Linux solution.

> +             for interf in $(ifconfig -s | cut -f1 -d' ') ; do
> +                     [ "$interf" = 'Iface' ] && continue
> +                     ifconfig  "$interf" | grep -q  'RUNNING' || continue
> +                     if [ -n "$family" ]; then
> +                             ifconfig "$interf" | grep -q $family || continue
> +                     fi
> +                     case $scope in #scopeid global=0x0, link=0x20, 
> host=0x10;
> +                             global) # ok='scopeid 0x0<global>'
> +                             ifconfig "$interf" | grep -Eq ' scopeid 
> 0x0<global>' && exit 0
> +                             ;;
> +                             link) #ok=0x20,0x0; rule out 0x10
> +                             ifconfig "$interf" | grep -Evq ' scopeid 0x10' 
> && exit 0
> +                             ;;
> +                             host) #ok= 0, 253, 254
> +                             #ifconfig "$interf" | grep -Eq ' scopeid 
> 0x[012]' && exit 0
> +                             exit 0
> +                             ;;
> +                     esac
> +#                    if [ -x /usr/sbin/iwconfig ]; then ... TODO wireless

Why do we need a wireless section? This script should be agnostic to the
type of physical interface.

> +             done
> +     fi
> +sleep 0.5
> +[ $i -eq '14' ] && break #timeout, 7 sec
> +done
> +
> +exit 111
> diff --git a/debian/runit-services.install b/debian/runit-services.install
> index 6cd3e7b..362650f 100644
> --- a/debian/runit-services.install
> +++ b/debian/runit-services.install
> @@ -1,2 +1,3 @@
>  debian/extra/rsyslog-rotate-runit       /usr/lib/rsyslog/
>  debian/extra/aa-rsyslog-runit            
> /usr/share/runit-services/logrotate.d
> +debian/extra/netcheck                      /usr/lib/runit-services/
> -- 
> 2.51.0
> 

Sorry again for my tardiness and I hope you don't mind my doubts!

Andrew

Reply via email to