[PATCH 00/10] Declarative static networking interface

DoneSubmitted by Ludovic Courtès.
Details
6 participants
  • Jonathan Brielmaier
  • Julien Lepiller
  • Ludovic Courtès
  • Mathieu Othacehe
  • David Aaron Fendley
  • Vivien Kraus
Owner
unassigned
Severity
normal
L
L
Ludovic Courtès wrote on 27 Oct 2021 15:59
(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027135918.18833-1-ludo@gnu.org
Hi!

This patch set builds on Julien’s neat Guile-Netlink to finally
provide a proper static networking configuration interface. One
can now write things like:

(service static-networking-service-type
;; Network configuration for one NIC, IPv4 + IPv6.
(static-networking
(addresses (list (network-address
(device "eno1")
(value "10.0.2.15/24"))
(network-address
(device "eno1")
(value "2001:123:4567:101::1"))))
(routes (list (network-route
(destination "default")
(gateway "10.0.2.2"))
(network-route
(destination "default")
(gateway "2020:321:4567:42::1"))))
(name-servers '("10.0.2.3"))))

For the record, the ‘static-networking-service’ procedure currently
in ‘master’ is IPv4-only and would not allow you to assign more
than one address to an interface anyway, among other limitations.
These long-overdue patches close an embarrassing gap.

The interface provided here is a direct mapping of that of Guile-Netlink,
which is the same as that of the ‘ip’ command, itself closely
modeled after Linux’s internal interfaces AIUI. Thus, it should be
roughly as expressive as ‘ip’, but declarative.

I’m not a network person though, so I’d appreciate if more
knowledgeable people would take a look at the interface. In particular,
I’d like to have examples of ‘links’ to include in the manual—I’m not
quite sure how to use that. Ideas?

This patches preserve backward-compatibility: the
‘static-networking-service’ procedure still works the same. There’s
one observable difference though: there’s only one ‘networking’
Shepherd service now; you no longer get ‘networking-eno1’ and similar.
The ‘static-networking’ constructor was public since commit
c9436025a90b86047ba2203d58bbf238f8f9b2f9 but undocumented; thus I
changed the fields of <static-networking> without worrying about
compatibility.

I tested this with:

make check-system \
TESTS="static-networking openvswitch ganeti-kvm dhcpd childhurd"

I would appreciate more testing, including tests on the bare metal
for IPv6 support.

Ensuring portability to GNU/Hurd took me more time than I’d have
thought, but it works. “Links” are not supported there, and only
“default” routes are supported.

I took a detour in commit “Use Guile-Netlink on GNU/Linux”: that
patch shows that I was blissfully hoping to use good’ol ioctls
on GNU/Hurd, but that turned out to be a dead end because they
don’t support IPv6 (which really isn’t a surprise but I don’t know,
I must have been lacking focus at that point of my journey!).

With all this I think we should be able to do “cool things with
containers”, but again, that’s not my area of expertise so please
do chime in if you container networking is your thing.

Feedback welcome!

Ludo’.

Ludovic Courtès (10):
tests: Add 'static-networking' test.
tests: openvswitch: Check whether ovs0 is up.
doc: Add new "Networking Setup" node for the main setup options.
gnu: guile-netlink: Allow cross-compilation.
services: static-networking: Use Guile-Netlink on GNU/Linux.
services: secret-service: Turn into a Shepherd service.
services: static-networking: Change interface to mimic netlink.
services: Define '%qemu-static-networking'.
services: Define '%loopback-static-networking'.
tests: Replace uses of deprecated 'static-networking-service'.

doc/guix.texi | 505 ++++++++++++++++++++++----------
gnu/build/hurd-boot.scm | 10 +-
gnu/build/secret-service.scm | 17 +-
gnu/packages/guile-xyz.scm | 11 +-
gnu/services/base.scm | 391 +++++++++++++++++++------
gnu/services/virtualization.scm | 45 ++-
gnu/system/hurd.scm | 12 +-
gnu/system/install.scm | 5 +-
gnu/tests/ganeti.scm | 7 +-
gnu/tests/networking.scm | 141 ++++++++-
10 files changed, 851 insertions(+), 293 deletions(-)


base-commit: 0a42998a50e8bbe9e49142b21a570db00efe7491
--
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 01/10] tests: Add 'static-networking' test.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-1-ludo@gnu.org
* gnu/tests/networking.scm (run-static-networking-test): New procedure.
(%test-static-networking): New variable.
---
gnu/tests/networking.scm | 99 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 97 insertions(+), 2 deletions(-)

Toggle diff (119 lines)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 453e63f52d..5da1c91da6 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -4,6 +4,7 @@
 ;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
 ;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
 ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -37,8 +38,102 @@ (define-module (gnu tests networking)
   #:use-module (gnu packages guile)
   #:use-module (gnu services shepherd)
   #:use-module (ice-9 match)
-  #:export (%test-inetd %test-openvswitch %test-dhcpd %test-tor %test-iptables
-                        %test-ipfs))
+  #:export (%test-static-networking
+            %test-inetd
+            %test-openvswitch
+            %test-dhcpd
+            %test-tor
+            %test-iptables
+            %test-ipfs))
+
+
+;;;
+;;; Static networking.
+;;;
+
+(define (run-static-networking-test vm)
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build syscalls))
+      #~(begin
+          (use-modules (gnu build marionette)
+                       (guix build syscalls)
+                       (srfi srfi-64))
+
+          (define marionette
+            (make-marionette
+             '(#$vm "-nic" "user,model=virtio-net-pci")))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "static-networking")
+
+          (test-assert "service is up"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'networking))
+             marionette))
+
+          (test-assert "network interfaces"
+            (marionette-eval
+             '(begin
+                (use-modules (guix build syscalls))
+                (network-interface-names))
+             marionette))
+
+          (test-equal "address of eth0"
+            "10.0.2.15"
+            (marionette-eval
+             '(let* ((sock (socket AF_INET SOCK_STREAM 0))
+                     (addr (network-interface-address sock "eth0")))
+                (close-port sock)
+                (inet-ntop (sockaddr:fam addr) (sockaddr:addr addr)))
+             marionette))
+
+          (test-equal "netmask of eth0"
+            "255.255.255.0"
+            (marionette-eval
+             '(let* ((sock (socket AF_INET SOCK_STREAM 0))
+                     (mask (network-interface-netmask sock "eth0")))
+                (close-port sock)
+                (inet-ntop (sockaddr:fam mask) (sockaddr:addr mask)))
+             marionette))
+
+          (test-equal "eth0 is up"
+            IFF_UP
+            (marionette-eval
+             '(let* ((sock  (socket AF_INET SOCK_STREAM 0))
+                     (flags (network-interface-flags sock "eth0")))
+                (logand flags IFF_UP))
+             marionette))
+
+          (test-end)
+
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "static-networking" test))
+
+(define %test-static-networking
+  (system-test
+   (name "static-networking")
+   (description "Test the 'static-networking' service.")
+   (value
+    (let ((os (marionette-operating-system
+               (simple-operating-system
+                (static-networking-service "eth0" "10.0.2.15"
+                                           #:netmask "255.255.255.0"
+                                           #:gateway "10.0.2.2"
+                                           #:name-servers '("10.0.2.2")))
+               #:imported-modules '((gnu services herd)
+                                    (guix combinators)))))
+      (run-static-networking-test (virtual-machine os))))))
+
+
+;;;
+;;; Inetd.
+;;;
 
 (define %inetd-os
   ;; Operating system with 2 inetd services.
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 02/10] tests: openvswitch: Check whether ovs0 is up.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-2-ludo@gnu.org
* gnu/tests/networking.scm (run-openvswitch-test)["ovs0 is up"]: New test.
---
gnu/tests/networking.scm | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

Toggle diff (43 lines)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 5da1c91da6..131428c128 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -286,12 +286,15 @@ (define %openvswitch-os
 (define (run-openvswitch-test)
   (define os
     (marionette-operating-system %openvswitch-os
-                                 #:imported-modules '((gnu services herd))))
+                                 #:imported-modules '((gnu services herd)
+                                                      (guix build syscalls))))
 
   (define test
-    (with-imported-modules '((gnu build marionette))
+    (with-imported-modules '((gnu build marionette)
+                             (guix build syscalls))
       #~(begin
           (use-modules (gnu build marionette)
+                       (guix build syscalls)
                        (ice-9 popen)
                        (ice-9 rdelim)
                        (srfi srfi-64))
@@ -339,6 +342,18 @@ (define marionette
                        (current-services))))
              marionette))
 
+          (test-equal "ovs0 is up"
+            IFF_UP
+            (marionette-eval
+             '(begin
+                (use-modules (guix build syscalls))
+
+                (let* ((sock  (socket AF_INET SOCK_STREAM 0))
+                       (flags (network-interface-flags sock "ovs0")))
+                  (close-port sock)
+                  (logand flags IFF_UP)))
+             marionette))
+
           (test-end)
           (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
 
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 04/10] gnu: guile-netlink: Allow cross-compilation.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-4-ludo@gnu.org
* gnu/packages/guile-xyz.scm (guile-netlink)[arguments]: Add #:phases.
Remove unnecessary #:tests? #f.
[native-inputs]: Add GUILE-3.0.
---
gnu/packages/guile-xyz.scm | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

Toggle diff (30 lines)
diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index 355b23f57e..daef8bbb26 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -4854,13 +4854,22 @@ (define-public guile-netlink
          "03zmsha2d7whlwb52gna83jdas9bqi18rq3sss7kkicv814qb35g"))))
     (build-system gnu-build-system)
     (arguments
-     `(#:tests? #f)); no tests
+     `(#:phases (modify-phases %standard-phases
+                  (add-before 'bootstrap 'set-guile-target
+                    (lambda* (#:key target #:allow-other-keys)
+                      (when target
+                        ;; Pass '--target=TRIPLET' to 'guild compile'.
+                        (substitute* "guile.am"
+                          (("\\$\\(GUILD\\) compile")
+                           (string-append "$(GUILD) compile --target="
+                                          target " ")))))))))
     (inputs
      `(("guile" ,guile-3.0)))
     (native-inputs
      `(("automake" ,automake)
        ("autoconf" ,autoconf)
        ("pkg-config" ,pkg-config)
+       ("guile" ,guile-3.0)                    ;for 'guild compile' + guile.m4
        ("texinfo" ,texinfo)))
     (home-page "https://git.lepiller.eu/guile-netlink")
     (synopsis "Netlink protocol implementation for Guile")
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 03/10] doc: Add new "Networking Setup" node for the main setup options.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-3-ludo@gnu.org
This should make it easier to find how to get started setting up
networking.

* doc/guix.texi (Networking Setup): New section.
(Networking Services): Remove 'static-networking-service',
'dhcp-client-service-type', 'network-manager-service-type',
'connman-service-type', 'wicd-service', 'modem-manager-service-type',
'usb-modeswitch-service-type', and 'wpa-supplicant-service-type'.
---
doc/guix.texi | 289 ++++++++++++++++++++++++++++----------------------
1 file changed, 160 insertions(+), 129 deletions(-)

Toggle diff (342 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 22215214e0..f7de378bdd 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -342,7 +342,8 @@ Services
 * Base Services::               Essential system services.
 * Scheduled Job Execution::     The mcron service.
 * Log Rotation::                The rottlog service.
-* Networking Services::         Network setup, SSH daemon, etc.
+* Networking Setup::            Setting up network interfaces.
+* Networking Services::         Firewall, SSH daemon, etc.
 * Unattended Upgrades::         Automated system upgrades.
 * X Window::                    Graphical display.
 * Printing Services::           Local and remote printer support.
@@ -15516,7 +15517,8 @@ declaration.
 * Base Services::               Essential system services.
 * Scheduled Job Execution::     The mcron service.
 * Log Rotation::                The rottlog service.
-* Networking Services::         Network setup, SSH daemon, etc.
+* Networking Setup::            Setting up network interfaces.
+* Networking Services::         Firewall, SSH daemon, etc.
 * Unattended Upgrades::         Automated system upgrades.
 * X Window::                    Graphical display.
 * Printing Services::           Local and remote printer support.
@@ -16738,63 +16740,26 @@ The list of syslog-controlled files to be rotated.  By default it is:
 "/var/log/maillog")}.
 @end defvr
 
-@node Networking Services
-@subsection Networking Services
+@node Networking Setup
+@subsection Networking Setup
 
-The @code{(gnu services networking)} module provides services to configure
-the network interface.
+The @code{(gnu services networking)} module provides services to
+configure network interfaces and set up networking on your machine.
+Those services provide different ways for you to set up your machine: by
+declaring a static network configuration, by running a Dynamic Host
+Configuration Protocol (DHCP) client, or by running daemons such as
+NetworkManager and Connman that automate the whole process,
+automatically adapt to connectivity changes, and provide a high-level
+user interface.
 
-@cindex DHCP, networking service
-@defvr {Scheme Variable} dhcp-client-service-type
-This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
-Protocol (DHCP) client, on all the non-loopback network interfaces.  Its value
-is the DHCP client package to use, @code{isc-dhcp} by default.
-@end defvr
+On a laptop, NetworkManager and Connman are by far the most convenient
+options, which is why the default desktop services include
+NetworkManager (@pxref{Desktop Services, @code{%desktop-services}}).
+For a server, or for a virtual machine or a container, static network
+configuration or a simple DHCP client are often more appropriate.
 
-@deffn {Scheme Procedure} dhcpd-service-type
-This type defines a service that runs a DHCP daemon.  To create a
-service of this type, you must supply a @code{<dhcpd-configuration>}.
-For example:
-
-@lisp
-(service dhcpd-service-type
-         (dhcpd-configuration
-          (config-file (local-file "my-dhcpd.conf"))
-          (interfaces '("enp0s25"))))
-@end lisp
-@end deffn
-
-@deftp {Data Type} dhcpd-configuration
-@table @asis
-@item @code{package} (default: @code{isc-dhcp})
-The package that provides the DHCP daemon.  This package is expected to
-provide the daemon at @file{sbin/dhcpd} relative to its output
-directory.  The default package is the
-@uref{https://www.isc.org/products/DHCP, ISC's DHCP server}.
-@item @code{config-file} (default: @code{#f})
-The configuration file to use.  This is required.  It will be passed to
-@code{dhcpd} via its @code{-cf} option.  This may be any ``file-like''
-object (@pxref{G-Expressions, file-like objects}).  See @code{man
-dhcpd.conf} for details on the configuration file syntax.
-@item @code{version} (default: @code{"4"})
-The DHCP version to use.  The ISC DHCP server supports the values ``4'',
-``6'', and ``4o6''.  These correspond to the @code{dhcpd} program
-options @code{-4}, @code{-6}, and @code{-4o6}.  See @code{man dhcpd} for
-details.
-@item @code{run-directory} (default: @code{"/run/dhcpd"})
-The run directory to use.  At service activation time, this directory
-will be created if it does not exist.
-@item @code{pid-file} (default: @code{"/run/dhcpd/dhcpd.pid"})
-The PID file to use.  This corresponds to the @code{-pf} option of
-@code{dhcpd}.  See @code{man dhcpd} for details.
-@item @code{interfaces} (default: @code{'()})
-The names of the network interfaces on which dhcpd should listen for
-broadcasts.  If this list is not empty, then its elements (which must be
-strings) will be appended to the @code{dhcpd} invocation when starting
-the daemon.  It may not be necessary to explicitly specify any
-interfaces here; see @code{man dhcpd} for details.
-@end table
-@end deftp
+This section describes the various network setup services available,
+starting with static network configuration.
 
 @defvr {Scheme Variable} static-networking-service-type
 This is the type for statically-configured network interfaces.
@@ -16824,81 +16789,13 @@ For example:
 @end lisp
 @end deffn
 
-@cindex wicd
-@cindex wireless
-@cindex WiFi
-@cindex network management
-@deffn {Scheme Procedure} wicd-service [#:wicd @var{wicd}]
-Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
-management daemon that aims to simplify wired and wireless networking.
-
-This service adds the @var{wicd} package to the global profile, providing
-several commands to interact with the daemon and configure networking:
-@command{wicd-client}, a graphical user interface, and the @command{wicd-cli}
-and @command{wicd-curses} user interfaces.
-@end deffn
-
-@cindex ModemManager
-
-@defvr {Scheme Variable} modem-manager-service-type
-This is the service type for the
-@uref{https://wiki.gnome.org/Projects/ModemManager, ModemManager}
-service.  The value for this service type is a
-@code{modem-manager-configuration} record.
-
-This service is part of @code{%desktop-services} (@pxref{Desktop
-Services}).
+@cindex DHCP, networking service
+@defvr {Scheme Variable} dhcp-client-service-type
+This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
+Protocol (DHCP) client, on all the non-loopback network interfaces.  Its value
+is the DHCP client package to use, @code{isc-dhcp} by default.
 @end defvr
 
-@deftp {Data Type} modem-manager-configuration
-Data type representing the configuration of ModemManager.
-
-@table @asis
-@item @code{modem-manager} (default: @code{modem-manager})
-The ModemManager package to use.
-
-@end table
-@end deftp
-
-@cindex USB_ModeSwitch
-@cindex Modeswitching
-
-@defvr {Scheme Variable} usb-modeswitch-service-type
-This is the service type for the
-@uref{https://www.draisberghof.de/usb_modeswitch/, USB_ModeSwitch}
-service.  The value for this service type is
-a @code{usb-modeswitch-configuration} record.
-
-When plugged in, some USB modems (and other USB devices) initially present
-themselves as a read-only storage medium and not as a modem.  They need to be
-@dfn{modeswitched} before they are usable.  The USB_ModeSwitch service type
-installs udev rules to automatically modeswitch these devices when they are
-plugged in.
-
-This service is part of @code{%desktop-services} (@pxref{Desktop
-Services}).
-@end defvr
-
-@deftp {Data Type} usb-modeswitch-configuration
-Data type representing the configuration of USB_ModeSwitch.
-
-@table @asis
-@item @code{usb-modeswitch} (default: @code{usb-modeswitch})
-The USB_ModeSwitch package providing the binaries for modeswitching.
-
-@item @code{usb-modeswitch-data} (default: @code{usb-modeswitch-data})
-The package providing the device data and udev rules file used by
-USB_ModeSwitch.
-
-@item @code{config-file} (default: @code{#~(string-append #$usb-modeswitch:dispatcher "/etc/usb_modeswitch.conf")})
-Which config file to use for the USB_ModeSwitch dispatcher.  By default the
-config file shipped with USB_ModeSwitch is used which disables logging to
-@file{/var/log} among other default settings.  If set to @code{#f}, no config
-file is used.
-
-@end table
-@end deftp
-
 @cindex NetworkManager
 
 @defvr {Scheme Variable} network-manager-service-type
@@ -17035,6 +16932,139 @@ List of additional command-line arguments to pass to the daemon.
 @end table
 @end deftp
 
+@cindex wicd
+@cindex wireless
+@cindex WiFi
+@cindex network management
+@deffn {Scheme Procedure} wicd-service [#:wicd @var{wicd}]
+Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
+management daemon that aims to simplify wired and wireless networking.
+
+This service adds the @var{wicd} package to the global profile, providing
+several commands to interact with the daemon and configure networking:
+@command{wicd-client}, a graphical user interface, and the @command{wicd-cli}
+and @command{wicd-curses} user interfaces.
+@end deffn
+
+@cindex ModemManager
+Some networking devices such as modems require special care, and this is
+what the services below focus on.
+
+@defvr {Scheme Variable} modem-manager-service-type
+This is the service type for the
+@uref{https://wiki.gnome.org/Projects/ModemManager, ModemManager}
+service.  The value for this service type is a
+@code{modem-manager-configuration} record.
+
+This service is part of @code{%desktop-services} (@pxref{Desktop
+Services}).
+@end defvr
+
+@deftp {Data Type} modem-manager-configuration
+Data type representing the configuration of ModemManager.
+
+@table @asis
+@item @code{modem-manager} (default: @code{modem-manager})
+The ModemManager package to use.
+
+@end table
+@end deftp
+
+@cindex USB_ModeSwitch
+@cindex Modeswitching
+
+@defvr {Scheme Variable} usb-modeswitch-service-type
+This is the service type for the
+@uref{https://www.draisberghof.de/usb_modeswitch/, USB_ModeSwitch}
+service.  The value for this service type is
+a @code{usb-modeswitch-configuration} record.
+
+When plugged in, some USB modems (and other USB devices) initially present
+themselves as a read-only storage medium and not as a modem.  They need to be
+@dfn{modeswitched} before they are usable.  The USB_ModeSwitch service type
+installs udev rules to automatically modeswitch these devices when they are
+plugged in.
+
+This service is part of @code{%desktop-services} (@pxref{Desktop
+Services}).
+@end defvr
+
+@deftp {Data Type} usb-modeswitch-configuration
+Data type representing the configuration of USB_ModeSwitch.
+
+@table @asis
+@item @code{usb-modeswitch} (default: @code{usb-modeswitch})
+The USB_ModeSwitch package providing the binaries for modeswitching.
+
+@item @code{usb-modeswitch-data} (default: @code{usb-modeswitch-data})
+The package providing the device data and udev rules file used by
+USB_ModeSwitch.
+
+@item @code{config-file} (default: @code{#~(string-append #$usb-modeswitch:dispatcher "/etc/usb_modeswitch.conf")})
+Which config file to use for the USB_ModeSwitch dispatcher.  By default the
+config file shipped with USB_ModeSwitch is used which disables logging to
+@file{/var/log} among other default settings.  If set to @code{#f}, no config
+file is used.
+
+@end table
+@end deftp
+
+
+@node Networking Services
+@subsection Networking Services
+
+The @code{(gnu services networking)} module discussed in the previous
+section provides services for more advanced setups: providing a DHCP
+service for others to use, filtering packets with iptables or nftables,
+running a WiFi access point with @command{hostapd}, running the
+@command{inetd} ``superdaemon'', and more.  This section describes
+those.
+
+@deffn {Scheme Procedure} dhcpd-service-type
+This type defines a service that runs a DHCP daemon.  To create a
+service of this type, you must supply a @code{<dhcpd-configuration>}.
+For example:
+
+@lisp
+(service dhcpd-service-type
+         (dhcpd-configuration
+          (config-file (local-file "my-dhcpd.conf"))
+          (interfaces '("enp0s25"))))
+@end lisp
+@end deffn
+
+@deftp {Data Type} dhcpd-configuration
+@table @asis
+@item @code{package} (default: @code{isc-dhcp})
+The package that provides the DHCP daemon.  This package is expected to
+provide the daemon at @file{sbin/dhcpd} relative to its output
+directory.  The default package is the
+@uref{https://www.isc.org/products/DHCP, ISC's DHCP server}.
+@item @code{config-file} (default: @code{#f})
+The configuration file to use.  This is required.  It will be passed to
+@code{dhcpd} via its @code{-cf} option.  This may be any ``file-like''
+object (@pxref{G-Expressions, file-like objects}).  See @code{man
+dhcpd.conf} for details on the configuration file syntax.
+@item @code{version} (default: @code{"4"})
+The DHCP version to use.  The ISC DHCP server supports the values ``4'',
+``6'', and ``4o6''.  These correspond to the @code{dhcpd} program
+options @code{-4}, @code{-6}, and @code{-4o6}.  See @code{man dhcpd} for
+details.
+@item @code{run-directory} (default: @code{"/run/dhcpd"})
+The run directory to use.  At service activation time, this directory
+will be created if it does not exist.
+@item @code{pid-file} (default: @code{"/run/dhcpd/dhcpd.pid"})
+The PID file to use.  This corresponds to the @code{-pf} option of
+@code{dhcpd}.  See @code{man dhcpd} for details.
+@item @code{interfaces} (default: @code{'()})
+The names of the network interfaces on which dhcpd should listen for
+broadcasts.  If this list is not empty, then its elements (which must be
+strings) will be appended to the @code{dhcpd} invocation when starting
+the daemon.  It may not be necessary to explicitly specify any
+interfaces here; see @code{man dhcpd} for details.
+@end table
+@end deftp
+
 @cindex hostapd service, for Wi-Fi access points
 @cindex Wi-Fi access points, hostapd service
 @defvr {Scheme Variable} hostapd-service-type
@@ -17097,6 +17127,7 @@ network that can be seen on @code{wlan0}, by default.
 The service's value is a @code{hostapd-configuration} record.
 @end defvr
 
+
 @cindex iptables
 @defvr {Scheme Variable} iptables-service-type
 This is the service type to set up an iptables configuration.  iptables is a
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 05/10] services: static-networking: Use Guile-Netlink on GNU/Linux.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-5-ludo@gnu.org
* gnu/services/base.scm (static-networking-shepherd-service): Define
'set-up-via-ioctl', 'tear-down-via-ioctl', 'set-up-via-netlink',
'tear-down-via-netlink', and 'helpers' and use them in 'start' and
'stop'. Add (ip *) modules to 'modules'.
---
gnu/services/base.scm | 102 +++++++++++++++++++++++++++++-------------
1 file changed, 72 insertions(+), 30 deletions(-)

Toggle diff (131 lines)
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 50865055fe..d5ee03bbbd 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -53,6 +53,7 @@ (define-module (gnu services base)
   #:use-module (gnu packages bash)
   #:use-module ((gnu packages base)
                 #:select (coreutils glibc glibc-utf8-locales))
+  #:autoload   (gnu packages guile-xyz) (guile-netlink)
   #:use-module (gnu packages package-management)
   #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
   #:use-module (gnu packages linux)
@@ -2336,6 +2337,66 @@ (define static-networking-shepherd-service
     (($ <static-networking> interface ip netmask gateway provision
                             requirement name-servers)
      (let ((loopback? (and provision (memq 'loopback provision))))
+       (define set-up-via-ioctl
+         #~(let* ((addr     (inet-pton AF_INET #$ip))
+                  (sockaddr (make-socket-address AF_INET addr 0))
+                  (mask     (and #$netmask (inet-pton AF_INET #$netmask)))
+                  (maskaddr (and mask
+                                 (make-socket-address AF_INET mask 0)))
+                  (gateway  (and #$gateway
+                                 (inet-pton AF_INET #$gateway)))
+                  (gatewayaddr (and gateway
+                                    (make-socket-address AF_INET
+                                                         gateway 0))))
+             (configure-network-interface #$interface sockaddr
+                                          (logior IFF_UP
+                                                  #$(if loopback?
+                                                        #~IFF_LOOPBACK
+                                                        0))
+                                          #:netmask maskaddr)
+             (when gateway
+               (let ((sock (socket AF_INET SOCK_DGRAM 0)))
+                 (add-network-route/gateway sock gatewayaddr)
+                 (close-port sock)))))
+
+       (define tear-down-via-ioctl
+         #~(let ((sock (socket AF_INET SOCK_STREAM 0)))
+             (when #$gateway
+               (delete-network-route sock
+                                     (make-socket-address AF_INET
+                                                          INADDR_ANY 0)))
+             (set-network-interface-flags sock #$interface 0)
+             (close-port sock)
+             #f))
+
+       (define set-up-via-netlink
+         (with-extensions (list guile-netlink)
+           #~(let ((ip #$(if netmask
+                             #~(ip+netmask->cidr #$ip #$netmask)
+                             ip)))
+               (addr-add #$interface ip)
+               (when #$gateway
+                 (route-add "default" #:device #$interface
+                            #:via #$gateway))
+               (link-set #$interface #:up #t))))
+
+       (define tear-down-via-netlink
+         (with-extensions (list guile-netlink)
+           #~(begin
+               (link-set #$interface #:down #t)
+               (when #$gateway
+                 (route-del "default" #:device #$interface))
+               (addr-del #$interface #$ip)
+               #f)))
+
+       (define helpers
+         #~(define (ip+netmask->cidr ip netmask)
+             ;; Return the CIDR notation (a string) for IP and NETMASK, two
+             ;; IPv4 address strings.
+             (let* ((netmask (inet-pton AF_INET netmask))
+                    (bits    (logcount netmask)))
+               (string-append ip "/" (number->string bits)))))
+
        (shepherd-service
 
         (documentation
@@ -2347,38 +2408,19 @@ (define static-networking-shepherd-service
 
         (start #~(lambda _
                    ;; Return #t if successfully started.
-                   (let* ((addr     (inet-pton AF_INET #$ip))
-                          (sockaddr (make-socket-address AF_INET addr 0))
-                          (mask     (and #$netmask
-                                         (inet-pton AF_INET #$netmask)))
-                          (maskaddr (and mask
-                                         (make-socket-address AF_INET
-                                                              mask 0)))
-                          (gateway  (and #$gateway
-                                         (inet-pton AF_INET #$gateway)))
-                          (gatewayaddr (and gateway
-                                            (make-socket-address AF_INET
-                                                                 gateway 0))))
-                     (configure-network-interface #$interface sockaddr
-                                                  (logior IFF_UP
-                                                          #$(if loopback?
-                                                                #~IFF_LOOPBACK
-                                                                0))
-                                                  #:netmask maskaddr)
-                     (when gateway
-                       (let ((sock (socket AF_INET SOCK_DGRAM 0)))
-                         (add-network-route/gateway sock gatewayaddr)
-                         (close-port sock))))))
+                   #$helpers
+                   (if (string-contains %host-type "-linux")
+                       #$set-up-via-netlink
+                       #$set-up-via-ioctl)))
         (stop #~(lambda _
                   ;; Return #f is successfully stopped.
-                  (let ((sock (socket AF_INET SOCK_STREAM 0)))
-                    (when #$gateway
-                      (delete-network-route sock
-                                            (make-socket-address
-                                             AF_INET INADDR_ANY 0)))
-                    (set-network-interface-flags sock #$interface 0)
-                    (close-port sock)
-                    #f)))
+                  (if (string-contains %host-type "-linux")
+                      #$tear-down-via-netlink
+                      #$tear-down-via-ioctl)))
+        (modules `((ip addr)
+                   (ip link)
+                   (ip route)
+                   ,@%default-modules))
         (respawn? #f))))))
 
 (define (static-networking-etc-files interfaces)
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 06/10] services: secret-service: Turn into a Shepherd service.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-6-ludo@gnu.org
* gnu/services/virtualization.scm (secret-service-activation): Remove.
(secret-service-shepherd-services): New procedure.
(secret-service-type)[extensions]: Remove ACTIVATION-SERVICE-TYPE
extension. Add SHEPHERD-ROOT-SERVICE-TYPE and
USER-PROCESSES-SERVICE-TYPE extensions.
* gnu/build/secret-service.scm (delete-file*): New procedure.
(secret-service-receive-secrets): Use it.
---
gnu/build/secret-service.scm | 17 ++++++++++++-
gnu/services/virtualization.scm | 45 ++++++++++++++++++++++++---------
2 files changed, 49 insertions(+), 13 deletions(-)

Toggle diff (103 lines)
diff --git a/gnu/build/secret-service.scm b/gnu/build/secret-service.scm
index 46dcf1b9c3..4e183e11e8 100644
--- a/gnu/build/secret-service.scm
+++ b/gnu/build/secret-service.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -111,6 +111,15 @@ (define (send-files sock)
        (close-port sock)
        #f))))
 
+(define (delete-file* file)
+  "Ensure FILE does not exist."
+  (catch 'system-error
+    (lambda ()
+      (delete-file file))
+    (lambda args
+      (unless (= ENOENT (system-error-errno args))
+        (apply throw args)))))
+
 (define (secret-service-receive-secrets port)
   "Listen to local PORT and wait for a secret service client to send secrets.
 Write them to the file system.  Return the list of files installed on success,
@@ -170,6 +179,12 @@ (define (read-secrets port)
                    (log "installing file '~a' (~a bytes)...~%"
                         file size)
                    (mkdir-p (dirname file))
+
+                   ;; It could be that FILE already exists, for instance
+                   ;; because it has been created by a service's activation
+                   ;; snippet (e.g., SSH host keys).  Delete it.
+                   (delete-file* file)
+
                    (call-with-output-file file
                      (lambda (output)
                        (dump port output size)
diff --git a/gnu/services/virtualization.scm b/gnu/services/virtualization.scm
index bca5f56b87..e7d2a7b833 100644
--- a/gnu/services/virtualization.scm
+++ b/gnu/services/virtualization.scm
@@ -852,23 +852,44 @@ (define qemu-binfmt-service-type
 ;;; Secrets for guest VMs.
 ;;;
 
-(define (secret-service-activation port)
-  "Return an activation snippet that fetches sensitive material at local PORT,
+(define (secret-service-shepherd-services port)
+  "Return a Shepherd service that fetches sensitive material at local PORT,
 over TCP.  Reboot upon failure."
-  (with-imported-modules '((gnu build secret-service)
-                           (guix build utils))
-    #~(begin
-        (use-modules (gnu build secret-service))
-        (let ((sent (secret-service-receive-secrets #$port)))
-          (unless sent
-            (sleep 3)
-            (reboot))))))
+  ;; This is a Shepherd service, rather than an activation snippet, to make
+  ;; sure it is started once 'networking' is up so it can accept incoming
+  ;; connections.
+  (list
+   (shepherd-service
+    (documentation "Fetch secrets from the host at startup time.")
+    (provision '(secret-service-client))
+    (requirement '(loopback networking))
+    (modules '((gnu build secret-service)
+               (guix build utils)))
+    (start (with-imported-modules '((gnu build secret-service)
+                                    (guix build utils))
+             #~(lambda ()
+                 ;; Since shepherd's output port goes to /dev/log, write this
+                 ;; message to stderr so it's visible on the Mach console.
+                 (format (current-error-port)
+                         "receiving secrets from the host...~%")
+                 (force-output (current-error-port))
+
+                 (let ((sent (secret-service-receive-secrets #$port)))
+                   (unless sent
+                     (sleep 3)
+                     (reboot))))))
+    (stop #~(const #f)))))
 
 (define secret-service-type
   (service-type
    (name 'secret-service)
-   (extensions (list (service-extension activation-service-type
-                                        secret-service-activation)))
+   (extensions (list (service-extension shepherd-root-service-type
+                                        secret-service-shepherd-services)
+
+                     ;; Make every Shepherd service depend on
+                     ;; 'secret-service-client'.
+                     (service-extension user-processes-service-type
+                                        (const '(secret-service-client)))))
    (description
     "This service fetches secret key and other sensitive material over TCP at
 boot time.  This service is meant to be used by virtual machines (VMs) that
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 07/10] services: static-networking: Change interface to mimic netlink.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-7-ludo@gnu.org
* gnu/services/base.scm (<static-networking>)[interface, ip, netmask]
[gateway]: Remove.
[addresses, links, routes]: New fields.
[requirement]: Default to '(udev).
(<network-address>, <network-link>, <network-route>): New record types.
(ensure-no-separate-netmask, %ensure-no-separate-netmask): Remove.
(ipv6-address?, cidr->netmask, ip+netmask->cidr)
(network-set-up/hurd, network-tear-down/hurd)
(network-set-up/linux, network-tear-down/linux)
(static-networking->hurd-pfinet-options): New procedures.
(static-networking-shepherd-service): New procedure.
(static-networking-shepherd-services): Rewrite in terms of the above.
(static-networking-service): Deprecate. Adjust to new
'static-networking' API.
(%base-services): Likewise.
* gnu/system/install.scm (%installation-services): Likewise.
* gnu/system/hurd.scm (%base-services/hurd): Likewise, and separate
'loopback' from 'networking'.
* gnu/build/hurd-boot.scm (set-hurd-device-translators): Remove
"servers/socket/2".
* gnu/tests/networking.scm (run-openvswitch-test)["networking has
started on ovs0"]: Check for 'networking instead of 'networking-ovs0,
which is no longer provided.
* doc/guix.texi (Networking Setup): Document the new interface. Remove
documentation of 'static-networking-service'.
(Virtualization Services): Change Ganeti example to use the new
interface.
---
doc/guix.texi | 191 +++++++++++++++---
gnu/build/hurd-boot.scm | 10 +-
gnu/services/base.scm | 410 +++++++++++++++++++++++++++------------
gnu/system/hurd.scm | 27 ++-
gnu/system/install.scm | 11 +-
gnu/tests/networking.scm | 2 +-
6 files changed, 481 insertions(+), 170 deletions(-)

Toggle diff (807 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index f7de378bdd..b529a8db6c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16762,32 +16762,166 @@ This section describes the various network setup services available,
 starting with static network configuration.
 
 @defvr {Scheme Variable} static-networking-service-type
-This is the type for statically-configured network interfaces.
-@c TODO Document <static-networking> data structures.
+This is the type for statically-configured network interfaces.  Its
+value must be a list of @code{static-networking} records.  Each of them
+declares a set of @dfn{addresses}, @dfn{routes}, and @dfn{links}, as
+show below.
+
+@cindex network interface controller (NIC)
+@cindex NIC, networking interface controller
+Here is the simplest configuration, with only one network interface
+controller (NIC) and only IPv4 connectivity:
+
+@example
+;; Static networking for one NIC, IPv4-only.
+(service static-networking-service-type
+         (list (static-networking
+                (addresses
+                 (list (network-address
+                        (device "eno1")
+                        (value "10.0.2.15/24"))))
+                (routes
+                 (list (network-route
+                        (destination "default")
+                        (gateway "10.0.2.2"))))
+                (name-servers '("10.0.2.3")))))
+@end example
+
+The snippet above can be added to the @code{services} field of your
+operating system configuration (@pxref{Using the Configuration System}).
+It will configure your machine to have 10.0.2.15 as its IP address, with
+a 24-bit netmask for the local network---meaning that any 10.0.2.@var{x}
+address is on the local area network (LAN).  Traffic to addresses
+outside the local network is routed @i{via} 10.0.2.2.  Host names are
+resolved by sending domain name system (DNS) queries to 10.0.2.3.
 @end defvr
 
-@deffn {Scheme Procedure} static-networking-service @var{interface} @var{ip} @
-       [#:netmask #f] [#:gateway #f] [#:name-servers @code{'()}] @
-       [#:requirement @code{'(udev)}]
-Return a service that starts @var{interface} with address @var{ip}.  If
-@var{netmask} is true, use it as the network mask.  If @var{gateway} is true,
-it must be a string specifying the default network gateway.  @var{requirement}
-can be used to declare a dependency on another service before configuring the
-interface.
+@deftp {Data Type} static-networking
+This is the data type representing a static network configuration.
 
-This procedure can be called several times, one for each network
-interface of interest.  Behind the scenes what it does is extend
-@code{static-networking-service-type} with additional network interfaces
-to handle.
-
-For example:
+As an example, here is how you would declare the configuration of a
+machine with a single network interface controller (NIC) available as
+@code{eno1}, and with one IPv4 and one IPv6 address:
 
 @lisp
-(static-networking-service "eno1" "192.168.1.82"
-                           #:gateway "192.168.1.2"
-                           #:name-servers '("192.168.1.2"))
+;; Network configuration for one NIC, IPv4 + IPv6.
+(static-networking
+ (addresses (list (network-address
+                   (device "eno1")
+                   (value "10.0.2.15/24"))
+                  (network-address
+                   (device "eno1")
+                   (value "2001:123:4567:101::1"))))
+ (routes (list (network-route
+                (destination "default")
+                (gateway "10.0.2.2"))
+               (network-route
+                (destination "default")
+                (gateway "2020:321:4567:42::1"))))
+ (name-servers '("10.0.2.3")))
 @end lisp
-@end deffn
+
+If you are familiar with the @command{ip} command of the
+@uref{https://wiki.linuxfoundation.org/networking/iproute2,
+@code{iproute2} package} found on Linux-based systems, the declaration
+above is equivalent to typing:
+
+@example
+ip address add 10.0.2.15/24 dev eno1
+ip address add 2001:123:4567:101::1 dev eno1
+ip route add default via inet 10.0.2.2
+ip route add default via inet6 2020:321:4567:42::1
+@end example
+
+Run @command{man 8 ip} for more info.  Venerable GNU/Linux users will
+certainly know how to do it with @command{ifconfig} and @command{route},
+but we'll spare you that.
+
+The available fields of this data type are as follows:
+
+@table @asis
+@item @code{addresses}
+@itemx @code{links} (default: @code{'()})
+@itemx @code{links} (default: @code{'()})
+The list of @code{network-address}, @code{network-link}, and
+@code{network-route} records for this network (see below).
+
+@item @code{name-servers} (default: @code{'()})
+The list of IP addresses (strings) of domain name servers.  These IP
+addresses go to @file{/etc/resolv.conf}.
+
+@item @code{provision} (default: @code{#f})
+If true, this should be a list of symbols for the Shepherd service
+corresponding to this network configuration.  When @code{#f},
+@code{'(networking)} or @code{'(loopback)} is used.
+
+@item @code{requirement} (default @code{'()})
+The list of Shepherd services depended on.
+@end table
+@end deftp
+
+@deftp {Data Type} network-address
+This is the data type representing the IP address of a network
+interface.
+
+@table @code
+@item device
+The name of the network interface for this address---e.g.,
+@code{"eno1"}.
+
+@item value
+The actual IP address and network mask, in
+@uref{https://en.wikipedia.org/wiki/CIDR#CIDR_notation, @acronym{CIDR,
+Classless Inter-Domain Routing} notation}, as a string.
+
+For example, @code{"10.0.2.15/24"} denotes IPv4 address 10.0.2.15 on a
+24-bit sub-network---all 10.0.2.@var{x} addresses are on the same local
+network.
+
+@item ipv6?
+Whether @code{value} denotes an IPv6 address.  By default this is
+automatically determined.
+@end table
+@end deftp
+
+@deftp {Data Type} network-route
+This is the data type representing a network route.
+
+@table @asis
+@item @code{destination}
+The route destination (a string), either an IP address or
+@code{"default"} to denote the default route.
+
+@item @code{source} (default: @code{#f})
+The route source.
+
+@item @code{device} (default: @code{#f})
+The device used for this route---e.g., @code{"eno2"}.
+
+@item @code{ipv6?} (default: auto)
+Whether this is an IPv6 route.  By default this is automatically
+determined based on @code{destination} or @code{gateway}.
+
+@item @code{gateway} (default: @code{#f})
+IP address (a string) through which traffic is routed.
+@end table
+@end deftp
+
+@deftp {Data Type} network-link
+Data type for a network link (@pxref{Link,,, guile-netlink,
+Guile-Netlink Manual}).
+
+@table @code
+@item name
+The name of the link---e.g., @code{"v0p0"}.
+
+@item type
+A symbol denoting the type of the link---e.g., @code{'veth}.
+
+@item arguments
+List of arguments for this type of link.
+@end table
+@end deftp
 
 @cindex DHCP, networking service
 @defvr {Scheme Variable} dhcp-client-service-type
@@ -30300,11 +30434,18 @@ cluster node that supports multiple storage backends, and installs the
                            "ganeti-instance-guix" "ganeti-instance-debootstrap"))
                     %base-packages))
   (services
-   (append (list (static-networking-service "eth0" "192.168.1.201"
-                                            #:netmask "255.255.255.0"
-                                            #:gateway "192.168.1.254"
-                                            #:name-servers '("192.168.1.252"
-                                                             "192.168.1.253"))
+   (append (list (service static-networking-service-type
+                          (list (static-networking
+                                 (addresses
+                                  (list (network-address
+                                         (device "eth0")
+                                         (value "192.168.1.201/24"))))
+                                 (routes
+                                  (list (network-route
+                                         (destination "default")
+                                         (gateway "192.168.1.254"))))
+                                 (name-servers '("192.168.1.252"
+                                                 "192.168.1.253")))))
 
                  ;; Ganeti uses SSH to communicate between nodes.
                  (service openssh-service-type
diff --git a/gnu/build/hurd-boot.scm b/gnu/build/hurd-boot.scm
index 8b27995438..ac36bd17d4 100644
--- a/gnu/build/hurd-boot.scm
+++ b/gnu/build/hurd-boot.scm
@@ -185,13 +185,9 @@ (define servers
       ("servers/crash-suspend"   ("/hurd/crash" "--suspend"))
       ("servers/password"        ("/hurd/password"))
       ("servers/socket/1"        ("/hurd/pflocal"))
-      ("servers/socket/2"        ("/hurd/pfinet"
-                                  "--interface" "eth0"
-                                  "--address"
-                                  "10.0.2.15" ;the default QEMU guest IP
-                                  "--netmask" "255.255.255.0"
-                                  "--gateway" "10.0.2.2"
-                                  "--ipv6" "/servers/socket/26"))
+      ;; /servers/socket/2 and /26 are created by 'static-networking-service'.
+      ;; XXX: Spawn pfinet without arguments on these nodes so that a DHCP
+      ;; client has someone to talk to?
       ("proc"                    ("/hurd/procfs" "--stat-mode=444"))))
 
   (define devices
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index d5ee03bbbd..03f6b388a8 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -35,6 +35,8 @@
 (define-module (gnu services base)
   #:use-module (guix store)
   #:use-module (guix deprecation)
+  #:autoload   (guix diagnostics) (warning)
+  #:autoload   (guix i18n) (G_)
   #:use-module (gnu services)
   #:use-module (gnu services admin)
   #:use-module (gnu services shepherd)
@@ -54,6 +56,7 @@ (define-module (gnu services base)
   #:use-module ((gnu packages base)
                 #:select (coreutils glibc glibc-utf8-locales))
   #:autoload   (gnu packages guile-xyz) (guile-netlink)
+  #:autoload   (gnu packages hurd) (hurd)
   #:use-module (gnu packages package-management)
   #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
   #:use-module (gnu packages linux)
@@ -81,14 +84,32 @@ (define-module (gnu services base)
             virtual-terminal-service-type
 
             static-networking
-
             static-networking?
-            static-networking-interface
-            static-networking-ip
-            static-networking-netmask
-            static-networking-gateway
+            static-networking-addresses
+            static-networking-links
+            static-networking-routes
             static-networking-requirement
 
+            network-address
+            network-address?
+            network-address-device
+            network-address-value
+            network-address-ipv6?
+
+            network-link
+            network-link?
+            network-link-name
+            network-link-type
+            network-link-arguments
+
+            network-route
+            network-route?
+            network-route-destination
+            network-route-source
+            network-route-device
+            network-route-ipv6?
+            network-route-gateway
+
             static-networking-service
             static-networking-service-type
 
@@ -2316,113 +2337,254 @@ (define kmscon-command
    (description "Start the @command{kmscon} virtual terminal emulator for the
 Linux @dfn{kernel mode setting} (KMS).")))
 
+
+;;;
+;;; Static networking.
+;;;
+
+(define (ipv6-address? str)
+  "Return true if STR denotes an IPv6 address."
+  (false-if-exception (->bool (inet-pton AF_INET6 str))))
+
 (define-record-type* <static-networking>
   static-networking make-static-networking
   static-networking?
-  (interface static-networking-interface)
-  (ip static-networking-ip)
-  (netmask static-networking-netmask
-           (default #f))
-  (gateway static-networking-gateway              ;FIXME: doesn't belong here
-           (default #f))
+  (addresses static-networking-addresses)         ;list of <network-address>
+  (links     static-networking-links (default '())) ;list of <network-link>
+  (routes    static-networking-routes (default '())) ;list of <network-routes>
   (provision static-networking-provision
              (default #f))
   (requirement static-networking-requirement
-               (default '()))
+               (default '(udev)))
   (name-servers static-networking-name-servers    ;FIXME: doesn't belong here
                 (default '())))
 
-(define static-networking-shepherd-service
+(define-record-type* <network-address>
+  network-address make-network-address
+  network-address?
+  (device    network-address-device)              ;string--e.g., "en01"
+  (value     network-address-value)               ;string--CIDR notation
+  (ipv6?     network-address-ipv6?                ;Boolean
+             (thunked)
+             (default
+               (ipv6-address? (cidr->ip (network-address-value this-record))))))
+
+(define-record-type* <network-link>
+  network-link make-network-link
+  network-link?
+  (name      network-link-name)                   ;string--e.g, "v0p0"
+  (type      network-link-type)                   ;symbol--e.g.,'veth
+  (arguments network-link-arguments))             ;list
+
+(define-record-type* <network-route>
+  network-route make-network-route
+  network-route?
+  (destination network-route-destination)
+  (source      network-route-source (default #f))
+  (device      network-route-device (default #f))
+  (ipv6?       network-route-ipv6? (thunked)
+               (default
+                 (or (ipv6-address? (network-route-destination this-record))
+                     (and=> (network-route-gateway this-record)
+                            ipv6-address?))))
+  (gateway     network-route-gateway (default #f)))
+
+(define* (cidr->netmask str #:optional (family AF_INET))
+  "Given @var{str}, a string in CIDR notation (e.g., \"1.2.3.4/24\"), return
+the netmask as a string like \"255.255.255.0\"."
+  (match (string-split str #\/)
+    ((ip (= string->number bits))
+     (let ((mask (ash (- (expt 2 bits) 1)
+                      (- (if (= family AF_INET6) 128 32)
+                         bits))))
+       (inet-ntop family mask)))
+    (_ #f)))
+
+(define (cidr->ip str)
+  "Strip the netmask bit of @var{str}, a CIDR-notation IP/netmask address."
+  (match (string-split str #\/)
+    ((or (ip _) (ip))
+     ip)))
+
+(define* (ip+netmask->cidr ip netmask #:optional (family AF_INET))
+  "Return the CIDR notation (a string) for @var{ip} and @var{netmask}, two
+@var{family} address strings, where @var{family} is @code{AF_INET} or
+@code{AF_INET6}."
+  (let* ((netmask (inet-pton family netmask))
+         (bits    (logcount netmask)))
+    (string-append ip "/" (number->string bits))))
+
+(define (static-networking->hurd-pfinet-options config)
+  "Return command-line options for the Hurd's pfinet translator corresponding
+to CONFIG."
+  (unless (null? (static-networking-links config))
+    ;; XXX: Presumably this is not supported, or perhaps could be approximated
+    ;; by running separate pfinet instances in some cases?
+    (warning (G_ "network links are currently ignored on GNU/Hurd~%")))
+
+  (match (static-networking-addresses config)
+    ((and addresses (first _ ...))
+     `("--ipv6" "/servers/socket/26"
+       "--interface" ,(network-address-device first)
+       ,@(append-map (lambda (address)
+                       `(,(if (network-address-ipv6? address)
+                              "--address6"
+                              "--address")
+                         ,(cidr->ip (network-address-value address))
+                         ,@(match (cidr->netmask (network-address-value address)
+                                                 (if (network-address-ipv6? address)
+                                                     AF_INET6
+                                                     AF_INET))
+                             (#f '())
+                             (mask (list "--netmask" mask)))))
+                     addresses)
+       ,@(append-map (lambda (route)
+                       (match route
+                         (($ <network-route> "default" #f device _ gateway)
+                          (if (network-route-ipv6? route)
+                              `("--gateway6" ,gateway)
+                              `("--gateway" ,gateway)))
+                         (($ <network-route> destination)
+                          (warning (G_ "ignoring network route for '~a'~%")
+                                   destination)
+                          '())))
+                     (static-networking-routes config))))))
+
+(define (network-set-up/hurd config)
+  "Set up networking for the Hurd."
+  ;; The Hurd implements SIOCGIFADDR and other old-style ioctls, but the only
+  ;; way to set up IPv6 is by starting pfinet with the right options.
+  (if (equal? (static-networking-provision config) '(loopback))
+      (scheme-file "set-up-pflocal" #~(begin 'nothing-to-do! #t))
+      (scheme-file "set-up-pfinet"
+                   (with-imported-modules '((guix build utils))
+                     #~(begin
+                         (use-modules (guix build utils)
+                                      (ice-9 format))
+
+                         ;; TODO: Do that without forking.
+                         (let ((options '#$(static-networking->hurd-pfinet-options
+                                            config)))
+                           (format #t "starting '~a~{ ~s~}'~%"
+                                   #$(file-append hurd "/hurd/pfinet")
+                                   options)
+                           (apply invoke #$(file-append hurd "/bin/settrans") "-fac"
+                                  "/servers/socket/2"
+                                  #$(file-append hurd "/hurd/pfinet")
+                                  options)))))))
+
+(define (network-tear-down/hurd config)
+  (scheme-file "tear-down-pfinet"
+               (with-imported-modules '((guix build utils))
+                 #~(begin
+                     (use-modules (guix build utils))
+
+                     ;; Forcefully terminate pfinet.  XXX: In theory this
+                     ;; should just undo the addresses and routes of CONFIG;
+                     ;; this could be done using ioctls like SIOCDELRT, but
+                     ;; these are IPv4-only; another option would be to use
+                     ;; fsysopts but that seems to crash pfinet.
+                     (invoke #$(file-append hurd "/bin/settrans") "-fg"
+                             "/servers/socket/2")
+                     #f))))
+
+(define network-set-up/linux
   (match-lambda
-    (($ <static-networking> interface ip netmask gateway provision
-                            requirement name-servers)
+    (($ <static-networking> addresses links routes)
+     (scheme-file "set-up-network"
+                  (with-extensions (list guile-netlink)
+                    #~(begin
+                        (use-modules (ip addr) (ip link) (ip route))
+
+                        #$@(map (lambda (address)
+                                  #~(begin
+                                      (addr-add #$(network-address-device address)
+                                                #$(network-address-value address)
+                                                #:ipv6?
+                                                #$(network-address-ipv6? address))
+                                      ;; FIXME: loopback?
+                                      (link-set #$(network-address-device address)
+                                                #:up #t)))
+                                addresses)
+                        #$@(map (match-lambda
+                                  (($ <network-link> name type arguments)
+                                   #~(link-add #:device #$name #$type
+                                               #:type-args '#$arguments)))
+                                links)
+                        #$@(map (lambda (route)
+                                  #~(route-add #$(network-route-destination route)
+                                               #:device
+                                               #$(network-route-device route)
+                                               #:ipv6?
+                                               #$(network-route-ipv6? route)
+                                               #:via
+                                               #$(network-route-gateway route)
+                                               #:src
+                                               #$(network-route-source route)))
+                                routes)
+                        #t))))))
+
+(define network-tear-down/linux
+  (match-lambda
+    (($ <static-networking> addresses links routes)
+     (scheme-file "set-up-network"
+                  (with-extensions (list guile-netlink)
+                    #~(begin
+                        (use-modules (ip addr) (ip link) (ip route))
+
+                        #$@(map (lambda (route)
+                                  #~(route-del #$(network-route-destination route)
+                                               #:device
+                                               #$(network-route-device route)
+                                               #:ipv6?
+                                               #$(network-route-ipv6? route)
+                                               #:via
+                                               #$(network-route-gateway route)
+                                               #:src
+                                               #$(network-route-source route)))
+                                routes)
+                        #$@(map (match-lambda
+                                  (($ <network-link> name type arguments)
+                                   #~(link-del #$name)))
+                                links)
+                        #$@(map (lambda (address)
+                                  #~(addr-del #$(network-address-device
+                                                 address)
+                                              #$(network-address-value address)
+                                              #:ipv6?
+                                              #$(network-address-ipv6? address)))
+                                addresses)
+                        #f))))))
+
+(define (static-networking-shepherd-service config)
+  (match config
+    (($ <static-networking> addresses links routes
+                            provision requirement name-servers)
      (let ((loopback? (and provision (memq 'loopback provision))))
-       (define set-up-via-ioctl
-         #~(let* ((addr     (inet-pton AF_INET #$ip))
-                  (sockaddr (make-socket-address AF_INET addr 0))
-                  (mask     (and #$netmask (inet-pton AF_INET #$netmask)))
-                  (maskaddr (and mask
-                                 (make-socket-address AF_INET mask 0)))
-                  (gateway  (and #$gateway
-                                 (inet-pton AF_INET #$gateway)))
-                  (gatewayaddr (and gateway
-                                    (make-socket-address AF_INET
-                                                         gateway 0))))
-             (configure-network-interface #$interface sockaddr
-                                          (logior IFF_UP
-                                                  #$(if loopback?
-                                                        #~IFF_LOOPBACK
-                                                        0))
-                                          #:netmask maskaddr)
-             (when gateway
-               (let ((sock (socket AF_INET SOCK_DGRAM 0)))
-                 (add-network-route/gateway sock gatewayaddr)
-                 (close-port sock)))))
-
-       (define tear-down-via-ioctl
-         #~(let ((sock (socket AF_INET SOCK_STREAM 0)))
-             (when #$gateway
-               (delete-network-route sock
-                                     (make-socket-address AF_INET
-                                                          INADDR_ANY 0)))
-             (set-network-interface-flags sock #$interface 0)
-             (close-port sock)
-             #f))
-
-       (define set-up-via-netlink
-         (with-extensions (list guile-netlink)
-           #~(let ((ip #$(if netmask
-                             #~(ip+netmask->cidr #$ip #$netmask)
-                             ip)))
-               (addr-add #$interface ip)
-               (when #$gateway
-                 (route-add "default" #:device #$interface
-                            #:via #$gateway))
-               (link-set #$interface #:up #t))))
-
-       (define tear-down-via-netlink
-         (with-extensions (list guile-netlink)
-           #~(begin
-               (link-set #$interface #:down #t)
-               (when #$gateway
-                 (route-del "default" #:device #$interface))
-               (addr-del #$interface #$ip)
-               #f)))
-
-       (define helpers
-         #~(define (ip+netmask->cidr ip netmask)
-             ;; Return the CIDR notation (a string) for IP and NETMASK, two
-             ;; IPv4 address strings.
-             (let* ((netmask (inet-pton AF_INET netmask))
-                    (bits    (logcount netmask)))
-               (string-append ip "/" (number->string bits)))))
-
        (shepherd-service
 
         (documentation
          "Bring up the networking interface using a static IP address.")
         (requirement requirement)
-        (provision (or provision
-                       (list (symbol-append 'networking-
-                                            (string->symbol interface)))))
+        (provision (or provision '(networking)))
 
         (start #~(lambda _
                    ;; Return #t if successfully started.
-                   #$helpers
-                   (if (string-contains %host-type "-linux")
-                       #$set-up-via-netlink
-                       #$set-up-via-ioctl)))
+                   (load #$(let-system (system target)
+                             (if (string-contains (or target system) "-linux")
+                                 (network-set-up/linux config)
+                                 (network-set-up/hurd config))))))
         (stop #~(lambda _
                   ;; Return #f is successfully stopped.
-                  (if (string-contains %host-type "-linux")
-                      #$tear-down-via-netlink
-                      #$tear-down-via-ioctl)))
-        (modules `((ip addr)
-                   (ip link)
-                   (ip route)
-                   ,@%default-modules))
+                  #$(let-system (system target)
+                      (if (string-contains (or target system) "-linux")
+                          (network-tear-down/linux config)
+                          (network-tear-down/hurd config)))))
         (respawn? #f))))))
 
+(define (static-networking-shepherd-services networks)
+  (map static-networking-shepherd-service networks))
+
 (define (static-networking-etc-files interfaces)
   "Return a /etc/resolv.conf entry for INTERFACES or the empty list."
   (match (delete-duplicates
@@ -2441,30 +2603,6 @@ (define (static-networking-etc-files interfaces)
 # Generated by 'static-networking-service'.\n"
                                       content))))))))
 
-(define (static-networking-shepherd-services interfaces)
-  "Return the list of Shepherd services to bring up INTERFACES, a list of
-<static-networking> objects."
-  (define (loopback? service)
-    (memq 'loopback (shepherd-service-provision service)))
-
-  (let ((services (map static-networking-shepherd-service interfaces)))
-    (match (remove loopback? services)
-      (()
-       ;; There's no interface other than 'loopback', so we assume that the
-       ;; 'networking' service will be provided by dhclient or similar.
-       services)
-      ((non-loopback ...)
-       ;; Assume we're providing all the interfaces, and thus, provide a
-       ;; 'networking' service.
-       (cons (shepherd-service
-              (provision '(networking))
-              (requirement (append-map shepherd-service-provision
-                                       services))
-              (start #~(const #t))
-              (stop #~(const #f))
-              (documentation "Bring up all the networking interfaces."))
-             services)))))
-
 (define static-networking-service-type
   ;; The service type for statically-defined network interfaces.
   (service-type (name 'static-networking)
@@ -2482,12 +2620,13 @@ (define static-networking-service-type
 services of this type is a list of @code{static-networking} objects, one per
 network interface.")))
 
-(define* (static-networking-service interface ip
-                                    #:key
-                                    netmask gateway provision
-                                    ;; Most interfaces require udev to be usable.
-                                    (requirement '(udev))
-                                    (name-servers '()))
+(define-deprecated (static-networking-service interface ip
+                                              #:key
+                                              netmask gateway provision
+                                              ;; Most interfaces require udev to be usable.
+                                              (requirement '(udev))
+                                              (name-servers '()))
+  static-networking-service-type
   "Return a service that starts @var{interface} with address @var{ip}.  If
 @var{netmask} is true, use it as the network mask.  If @var{gateway} is true,
 it must be a string specifying the default network gateway.
@@ -2498,11 +2637,24 @@ (define* (static-networking-service interface ip
 to handle."
   (simple-service 'static-network-interface
                   static-networking-service-type
-                  (list (static-networking (interface interface) (ip ip)
-                                           (netmask netmask) (gateway gateway)
-                                           (provision provision)
-                                           (requirement requirement)
-                                           (name-servers name-servers)))))
+                  (list (static-networking
+                         (addresses
+                          (list (network-address
+                                 (device interface)
+                                 (value (if netmask
+                                            (ip+netmask->cidr ip netmask)
+                                            ip))
+                                 (ipv6? #f))))
+                         (routes
+                          (if gateway
+                              (list (network-route
+                                     (destination "default")
+                                     (gateway gateway)
+                                     (ipv6? #f)))
+                              '()))
+                         (requirement requirement)
+                         (provision provision)
+                         (name-servers name-servers)))))
 
 
 (define %base-services
@@ -2534,10 +2686,12 @@ (define %base-services
                                          (tty "tty6")))
 
         (service static-networking-service-type
-                 (list (static-networking (interface "lo")
-                                          (ip "127.0.0.1")
-                                          (requirement '())
-                                          (provision '(loopback)))))
+                 (list (static-networking
+                        (addresses (list (network-address
+                                          (device "lo")
+                                          (value "127.0.0.1"))))
+                        (requirement '())
+                        (provision '(loopback)))))
         (syslog-service)
         (service urandom-seed-service-type)
         (service guix-service-type)
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index 0794671ce4..0e73ca0d99 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -79,11 +79,28 @@ (define %base-services/hurd
         (service hurd-getty-service-type (hurd-getty-configuration
                                           (tty "tty2")))
         (service static-networking-service-type
-                 (list (static-networking (interface "lo")
-                                          (ip "127.0.0.1")
-                                          (requirement '())
-                                          (provision '(loopback networking))
-                                          (name-servers '("10.0.2.3")))))
+                 (list (static-networking
+                        (addresses
+                         (list (network-address
+                                (device "lo")
+                                (value "127.0.0.1"))))
+                        (requirement '())
+                        (provision '(loopback)))
+                       (static-networking
+                        (addresses
+                         ;; The default QEMU guest address.  To get "eth0",
+                         ;; you need QEMU to emulate a device for which Mach
+                         ;; has an in-kernel driver, for instance with:
+                         ;; --device rtl8139,netdev=net0 --netdev user,id=net0
+                         (list (network-address
+                                (device "eth0")
+                                (value "10.0.2.15/24"))))
+                        (routes
+                         (list (network-route
+                                (destination "default")
+                                (gateway "10.0.2.2"))))
+                        (provision '(networking))
+                        (name-servers '("10.0.2.3")))))
         (syslog-service)
         (service guix-service-type
                  (guix-configuration
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index 7b394184ad..bdfe580145 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -408,10 +408,13 @@ (define bare-bones-os
 
           ;; Loopback device, needed by OpenSSH notably.
           (service static-networking-service-type
-                   (list (static-networking (interface "lo")
-                                            (ip "127.0.0.1")
-                                            (requirement '())
-                                            (provision '(loopback)))))
+                   (list (static-networking
+                          (addresses
+                           (list (network-address
+                                  (device "lo")
+                                  (value "127.0.0.1"))))
+                          (requirement '())
+                          (provision '(loopback)))))
 
           (service wpa-supplicant-service-type)
           (dbus-service)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 131428c128..c66af279f2 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -337,7 +337,7 @@ (define marionette
                              (srfi srfi-1))
                 (live-service-running
                  (find (lambda (live)
-                         (memq 'networking-ovs0
+                         (memq 'networking
                                (live-service-provision live)))
                        (current-services))))
              marionette))
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 08/10] services: Define '%qemu-static-networking'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-8-ludo@gnu.org
* gnu/services/base.scm (%qemu-static-networking): New variable.
* gnu/system/hurd.scm (%base-services/hurd): Use it.
* doc/guix.texi (Networking Setup): Document it.
---
doc/guix.texi | 8 ++++++++
gnu/services/base.scm | 16 ++++++++++++++++
gnu/system/hurd.scm | 21 ++++++---------------
3 files changed, 30 insertions(+), 15 deletions(-)

Toggle diff (87 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index b529a8db6c..0b23075d8c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16923,6 +16923,14 @@ List of arguments for this type of link.
 @end table
 @end deftp
 
+@cindex networking, with QEMU
+@cindex QEMU, networking
+@defvr {Scheme Variable} %qemu-static-networking
+This is the @code{static-networking} record representing network setup
+when using QEMU's user-mode network stack on @code{eth0} (@pxref{Using
+the user mode network stack,,, QEMU, QEMU Documentation}).
+@end defvr
+
 @cindex DHCP, networking service
 @defvr {Scheme Variable} dhcp-client-service-type
 This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 03f6b388a8..380be1c71e 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -113,6 +113,8 @@ (define-module (gnu services base)
             static-networking-service
             static-networking-service-type
 
+            %qemu-static-networking
+
             udev-configuration
             udev-configuration?
             udev-configuration-rules
@@ -2656,6 +2658,20 @@ (define-deprecated (static-networking-service interface ip
                          (provision provision)
                          (name-servers name-servers)))))
 
+(define %qemu-static-networking
+  ;; Networking configuration for QEMU's user-mode network stack (info "(QEMU)
+  ;; Using the user mode network stack").
+  (static-networking
+   (addresses (list (network-address
+                     (device "eth0")
+                     (value "10.0.2.15/24"))))
+   (routes (list (network-route
+                  (destination "default")
+                  (gateway "10.0.2.2"))))
+   (requirement '())
+   (provision '(networking))
+   (name-servers '("10.0.2.3"))))
+
 
 (define %base-services
   ;; Convenience variable holding the basic services.
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index 0e73ca0d99..ec8484d746 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -86,21 +86,12 @@ (define %base-services/hurd
                                 (value "127.0.0.1"))))
                         (requirement '())
                         (provision '(loopback)))
-                       (static-networking
-                        (addresses
-                         ;; The default QEMU guest address.  To get "eth0",
-                         ;; you need QEMU to emulate a device for which Mach
-                         ;; has an in-kernel driver, for instance with:
-                         ;; --device rtl8139,netdev=net0 --netdev user,id=net0
-                         (list (network-address
-                                (device "eth0")
-                                (value "10.0.2.15/24"))))
-                        (routes
-                         (list (network-route
-                                (destination "default")
-                                (gateway "10.0.2.2"))))
-                        (provision '(networking))
-                        (name-servers '("10.0.2.3")))))
+
+                       ;; QEMU user-mode networking.  To get "eth0", you need
+                       ;; QEMU to emulate a device for which Mach has an
+                       ;; in-kernel driver, for instance with:
+                       ;; --device rtl8139,netdev=net0 --netdev user,id=net0
+                       %qemu-static-networking))
         (syslog-service)
         (service guix-service-type
                  (guix-configuration
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 09/10] services: Define '%loopback-static-networking'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-9-ludo@gnu.org
* gnu/services/base.scm (%loopback-static-networking): New variable.
(%base-services): Use it.
* gnu/system/hurd.scm (%base-services/hurd): Use it.
* gnu/system/install.scm (%installation-services): Use it.
* doc/guix.texi (Networking Setup): Document it.
---
doc/guix.texi | 7 +++++++
gnu/services/base.scm | 17 +++++++++++------
gnu/system/hurd.scm | 8 +-------
gnu/system/install.scm | 8 +-------
4 files changed, 20 insertions(+), 20 deletions(-)

Toggle diff (100 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 0b23075d8c..b8b9cf2730 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16923,6 +16923,13 @@ List of arguments for this type of link.
 @end table
 @end deftp
 
+@cindex loopback device
+@defvr {Scheme Variable} %loopback-static-networking
+This is the @code{static-networking} record representing the ``loopback
+device'', @code{lo}, for IP addresses 127.0.0.1 and ::1, and providing
+the @code{loopback} Shepherd service.
+@end defvr
+
 @cindex networking, with QEMU
 @cindex QEMU, networking
 @defvr {Scheme Variable} %qemu-static-networking
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 380be1c71e..66683f153f 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -113,6 +113,7 @@ (define-module (gnu services base)
             static-networking-service
             static-networking-service-type
 
+            %loopback-static-networking
             %qemu-static-networking
 
             udev-configuration
@@ -2658,6 +2659,15 @@ (define-deprecated (static-networking-service interface ip
                          (provision provision)
                          (name-servers name-servers)))))
 
+(define %loopback-static-networking
+  ;; The loopback device.
+  (static-networking
+   (addresses (list (network-address
+                     (device "lo")
+                     (value "127.0.0.1"))))
+   (requirement '())
+   (provision '(loopback))))
+
 (define %qemu-static-networking
   ;; Networking configuration for QEMU's user-mode network stack (info "(QEMU)
   ;; Using the user mode network stack").
@@ -2702,12 +2712,7 @@ (define %base-services
                                          (tty "tty6")))
 
         (service static-networking-service-type
-                 (list (static-networking
-                        (addresses (list (network-address
-                                          (device "lo")
-                                          (value "127.0.0.1"))))
-                        (requirement '())
-                        (provision '(loopback)))))
+                 (list %loopback-static-networking))
         (syslog-service)
         (service urandom-seed-service-type)
         (service guix-service-type)
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index ec8484d746..2acc7b7e11 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -79,13 +79,7 @@ (define %base-services/hurd
         (service hurd-getty-service-type (hurd-getty-configuration
                                           (tty "tty2")))
         (service static-networking-service-type
-                 (list (static-networking
-                        (addresses
-                         (list (network-address
-                                (device "lo")
-                                (value "127.0.0.1"))))
-                        (requirement '())
-                        (provision '(loopback)))
+                 (list %loopback-static-networking
 
                        ;; QEMU user-mode networking.  To get "eth0", you need
                        ;; QEMU to emulate a device for which Mach has an
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index bdfe580145..073d7df1db 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -408,13 +408,7 @@ (define bare-bones-os
 
           ;; Loopback device, needed by OpenSSH notably.
           (service static-networking-service-type
-                   (list (static-networking
-                          (addresses
-                           (list (network-address
-                                  (device "lo")
-                                  (value "127.0.0.1"))))
-                          (requirement '())
-                          (provision '(loopback)))))
+                   (list %loopback-static-networking))
 
           (service wpa-supplicant-service-type)
           (dbus-service)
-- 
2.33.0
L
L
Ludovic Courtès wrote on 27 Oct 2021 16:02
[PATCH 10/10] tests: Replace uses of deprecated 'static-networking-service'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211027140245.18970-10-ludo@gnu.org
* gnu/tests/ganeti.scm (%ganeti-os): Replace call to
'static-networking-service' by instantiating
STATIC-NETWORKING-SERVICE-TYPE.
* gnu/tests/networking.scm (%test-static-networking)
(%openvswitch-os, %dhcpd-os): Likewise.
---
gnu/tests/ganeti.scm | 7 ++-----
gnu/tests/networking.scm | 29 ++++++++++++++++++-----------
2 files changed, 20 insertions(+), 16 deletions(-)

Toggle diff (74 lines)
diff --git a/gnu/tests/ganeti.scm b/gnu/tests/ganeti.scm
index 5ac2fd48dd..c29b885a5e 100644
--- a/gnu/tests/ganeti.scm
+++ b/gnu/tests/ganeti.scm
@@ -59,11 +59,8 @@ (define %ganeti-os
     (packages (append (list ganeti-instance-debootstrap ganeti-instance-guix)
                       %base-packages))
     (services
-     (append (list (static-networking-service "eth0" "10.0.2.15"
-                                              #:netmask "255.255.255.0"
-                                              #:gateway "10.0.2.2"
-                                              #:name-servers '("10.0.2.3"))
-
+     (append (list (service static-networking-service-type
+                            (list %qemu-static-networking))
                    (service openssh-service-type
                             (openssh-configuration
                              (permit-root-login 'prohibit-password)))
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index c66af279f2..246e0a15fa 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -122,10 +122,8 @@ (define %test-static-networking
    (value
     (let ((os (marionette-operating-system
                (simple-operating-system
-                (static-networking-service "eth0" "10.0.2.15"
-                                           #:netmask "255.255.255.0"
-                                           #:gateway "10.0.2.2"
-                                           #:name-servers '("10.0.2.2")))
+                (service static-networking-service-type
+                         (list %qemu-static-networking)))
                #:imported-modules '((gnu services herd)
                                     (guix combinators)))))
       (run-static-networking-test (virtual-machine os))))))
@@ -275,9 +273,13 @@ (define openvswitch-configuration-service
 (define %openvswitch-os
   (operating-system
     (inherit (simple-operating-system
-              (static-networking-service "ovs0" "10.1.1.1"
-                                         #:netmask "255.255.255.252"
-                                         #:requirement '(openvswitch-configuration))
+              (simple-service 'openswitch-networking
+                              static-networking-service-type
+                              (list (static-networking
+                                     (addresses (list (network-address
+                                                       (value "10.1.1.1/24")
+                                                       (device "ovs0"))))
+                                     (requirement '(openvswitch-configuration)))))
               (service openvswitch-service-type)
               openvswitch-configuration-service))
     ;; Ensure the interface name does not change depending on the driver.
@@ -392,10 +394,15 @@ (define dhcpd-v4-configuration
 
 (define %dhcpd-os
   (simple-operating-system
-   (static-networking-service "ens3" "192.168.1.4"
-                              #:netmask "255.255.255.0"
-                              #:gateway "192.168.1.1"
-                              #:name-servers '("192.168.1.2" "192.168.1.3"))
+   (service static-networking-service-type
+            (list (static-networking
+                   (addresses (list (network-address
+                                     (value "192.168.1.4/24")
+                                     (device "ens3"))))
+                   (routes (list (network-route
+                                  (destination "default")
+                                  (gateway "192.168.1.1"))))
+                   (name-servers '("192.168.1.2" "192.168.1.3")))))
    (service dhcpd-service-type dhcpd-v4-configuration)))
 
 (define (run-dhcpd-test)
-- 
2.33.0
J
J
Julien Lepiller wrote on 27 Oct 2021 17:29
Re: [bug#51440] [PATCH 00/10] Declarative static networking interface
98B14704-7A97-4D5A-80CD-6A44DBAEFBC7@lepiller.eu
Le 27 octobre 2021 09:59:18 GMT-04:00, "Ludovic Courtès" <ludo@gnu.org> a écrit :
Toggle quote (100 lines)
>Hi!
>
>This patch set builds on Julien’s neat Guile-Netlink to finally
>provide a proper static networking configuration interface. One
>can now write things like:
>
> (service static-networking-service-type
> ;; Network configuration for one NIC, IPv4 + IPv6.
> (static-networking
> (addresses (list (network-address
> (device "eno1")
> (value "10.0.2.15/24"))
> (network-address
> (device "eno1")
> (value "2001:123:4567:101::1"))))
> (routes (list (network-route
> (destination "default")
> (gateway "10.0.2.2"))
> (network-route
> (destination "default")
> (gateway "2020:321:4567:42::1"))))
> (name-servers '("10.0.2.3"))))
>
>For the record, the ‘static-networking-service’ procedure currently
>in ‘master’ is IPv4-only and would not allow you to assign more
>than one address to an interface anyway, among other limitations.
>These long-overdue patches close an embarrassing gap.
>
>The interface provided here is a direct mapping of that of Guile-Netlink,
>which is the same as that of the ‘ip’ command, itself closely
>modeled after Linux’s internal interfaces AIUI. Thus, it should be
>roughly as expressive as ‘ip’, but declarative.
>
>I’m not a network person though, so I’d appreciate if more
>knowledgeable people would take a look at the interface. In particular,
>I’d like to have examples of ‘links’ to include in the manual—I’m not
>quite sure how to use that. Ideas?
>
>This patches preserve backward-compatibility: the
>‘static-networking-service’ procedure still works the same. There’s
>one observable difference though: there’s only one ‘networking’
>Shepherd service now; you no longer get ‘networking-eno1’ and similar.
>The ‘static-networking’ constructor was public since commit
>c9436025a90b86047ba2203d58bbf238f8f9b2f9 but undocumented; thus I
>changed the fields of <static-networking> without worrying about
>compatibility.
>
>I tested this with:
>
> make check-system \
> TESTS="static-networking openvswitch ganeti-kvm dhcpd childhurd"
>
>I would appreciate more testing, including tests on the bare metal
>for IPv6 support.
>
>Ensuring portability to GNU/Hurd took me more time than I’d have
>thought, but it works. “Links” are not supported there, and only
>“default” routes are supported.
>
>I took a detour in commit “Use Guile-Netlink on GNU/Linux”: that
>patch shows that I was blissfully hoping to use good’ol ioctls
>on GNU/Hurd, but that turned out to be a dead end because they
>don’t support IPv6 (which really isn’t a surprise but I don’t know,
>I must have been lacking focus at that point of my journey!).
>
>With all this I think we should be able to do “cool things with
>containers”, but again, that’s not my area of expertise so please
>do chime in if you container networking is your thing.
>
>Feedback welcome!
>
>Ludo’.
>
>Ludovic Courtès (10):
> tests: Add 'static-networking' test.
> tests: openvswitch: Check whether ovs0 is up.
> doc: Add new "Networking Setup" node for the main setup options.
> gnu: guile-netlink: Allow cross-compilation.
> services: static-networking: Use Guile-Netlink on GNU/Linux.
> services: secret-service: Turn into a Shepherd service.
> services: static-networking: Change interface to mimic netlink.
> services: Define '%qemu-static-networking'.
> services: Define '%loopback-static-networking'.
> tests: Replace uses of deprecated 'static-networking-service'.
>
> doc/guix.texi | 505 ++++++++++++++++++++++----------
> gnu/build/hurd-boot.scm | 10 +-
> gnu/build/secret-service.scm | 17 +-
> gnu/packages/guile-xyz.scm | 11 +-
> gnu/services/base.scm | 391 +++++++++++++++++++------
> gnu/services/virtualization.scm | 45 ++-
> gnu/system/hurd.scm | 12 +-
> gnu/system/install.scm | 5 +-
> gnu/tests/ganeti.scm | 7 +-
> gnu/tests/networking.scm | 141 ++++++++-
> 10 files changed, 851 insertions(+), 293 deletions(-)
>
>
>base-commit: 0a42998a50e8bbe9e49142b21a570db00efe7491

Looks good at first glance. I noticed a few typos in the manual, so I'll send you more details after I read it more carefully. I'll try that on my hardware, although again I'm not sure how I can run reconfigure from my checkout exactly? (Where do I use sudo, and what options do I need)
J
J
Julien Lepiller wrote on 28 Oct 2021 02:58
Re: [bug#51440] [PATCH 04/10] gnu: guile-netlink: Allow cross-compilation.
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 51440@debbugs.gnu.org)
20211028025840.528e0b8e@tachikoma.lepiller.eu
Le Wed, 27 Oct 2021 16:02:39 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

Toggle quote (38 lines)
> * gnu/packages/guile-xyz.scm (guile-netlink)[arguments]: Add #:phases.
> Remove unnecessary #:tests? #f.
> [native-inputs]: Add GUILE-3.0.
> ---
> gnu/packages/guile-xyz.scm | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
> index 355b23f57e..daef8bbb26 100644
> --- a/gnu/packages/guile-xyz.scm
> +++ b/gnu/packages/guile-xyz.scm
> @@ -4854,13 +4854,22 @@ (define-public guile-netlink
> "03zmsha2d7whlwb52gna83jdas9bqi18rq3sss7kkicv814qb35g"))))
> (build-system gnu-build-system)
> (arguments
> - `(#:tests? #f)); no tests
> + `(#:phases (modify-phases %standard-phases
> + (add-before 'bootstrap 'set-guile-target
> + (lambda* (#:key target #:allow-other-keys)
> + (when target
> + ;; Pass '--target=TRIPLET' to 'guild
> compile'.
> + (substitute* "guile.am"
> + (("\\$\\(GUILD\\) compile")
> + (string-append "$(GUILD) compile
> --target="
> + target " ")))))))))
> (inputs
> `(("guile" ,guile-3.0)))
> (native-inputs
> `(("automake" ,automake)
> ("autoconf" ,autoconf)
> ("pkg-config" ,pkg-config)
> + ("guile" ,guile-3.0) ;for 'guild compile'
> + guile.m4 ("texinfo" ,texinfo)))
> (home-page "https://git.lepiller.eu/guile-netlink")
> (synopsis "Netlink protocol implementation for Guile")

Is there anything I can do as the author of guile-netlink to allow
cross-compilation?
J
J
Julien Lepiller wrote on 28 Oct 2021 03:17
Re: [bug#51440] [PATCH 07/10] services: static-networking: Change interface to mimic netlink.
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 51440@debbugs.gnu.org)
20211028031738.50dc8114@tachikoma.lepiller.eu
A few comments on the documentation below.

Le Wed, 27 Oct 2021 16:02:42 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

Toggle quote (21 lines)
> @lisp
> -(static-networking-service "eno1" "192.168.1.82"
> - #:gateway "192.168.1.2"
> - #:name-servers '("192.168.1.2"))
> +;; Network configuration for one NIC, IPv4 + IPv6.
> +(static-networking
> + (addresses (list (network-address
> + (device "eno1")
> + (value "10.0.2.15/24"))
> + (network-address
> + (device "eno1")
> + (value "2001:123:4567:101::1"))))
> + (routes (list (network-route
> + (destination "default")
> + (gateway "10.0.2.2"))
> + (network-route
> + (destination "default")
> + (gateway "2020:321:4567:42::1"))))
> + (name-servers '("10.0.2.3")))
> @end lisp

I don't know if you tested that, but I think this is not routable
because the IPv6 network doesn't have a netmask, so I think it defaults
to a /128 (one IP in the network), so the router is not on the local
network. Many ISPs provide a /64 (when the provide IPv6), so maybe use
that as the netmask?

Toggle quote (14 lines)
> -@end deffn
> +
> +If you are familiar with the @command{ip} command of the
> +@uref{https://wiki.linuxfoundation.org/networking/iproute2,
> +@code{iproute2} package} found on Linux-based systems, the
> declaration +above is equivalent to typing:
> +
> +@example
> +ip address add 10.0.2.15/24 dev eno1
> +ip address add 2001:123:4567:101::1 dev eno1
> +ip route add default via inet 10.0.2.2
> +ip route add default via inet6 2020:321:4567:42::1
> +@end example

And so, change it here too.

Toggle quote (11 lines)
> +Run @command{man 8 ip} for more info. Venerable GNU/Linux users will
> +certainly know how to do it with @command{ifconfig} and
> @command{route}, +but we'll spare you that.
> +
> +The available fields of this data type are as follows:
> +
> +@table @asis
> +@item @code{addresses}
> +@itemx @code{links} (default: @code{'()})
> +@itemx @code{links} (default: @code{'()})

One of them should be routes, right?

Toggle quote (5 lines)
> +@item @code{provision} (default: @code{#f})
> +If true, this should be a list of symbols for the Shepherd service
> +corresponding to this network configuration. When @code{#f},
> +@code{'(networking)} or @code{'(loopback)} is used.

Under which conditions is it 'loopback instead of 'networking?

Toggle quote (5 lines)
> +@item @code{requirement} (default @code{'()})
> +The list of Shepherd services depended on.
> +@end table
> +@end deftp

The rest of the manual changes look good :)
L
L
Ludovic Courtès wrote on 29 Oct 2021 23:38
Re: bug#51440: [PATCH 00/10] Declarative static networking interface
(name . Julien Lepiller)(address . julien@lepiller.eu)(address . 51440@debbugs.gnu.org)
874k8zy0is.fsf_-_@gnu.org
Hi,

Julien Lepiller <julien@lepiller.eu> skribis:

Toggle quote (3 lines)
> Le Wed, 27 Oct 2021 16:02:39 +0200,
> Ludovic Courtès <ludo@gnu.org> a écrit :

[...]

Toggle quote (7 lines)
>> + ;; Pass '--target=TRIPLET' to 'guild
>> compile'.
>> + (substitute* "guile.am"
>> + (("\\$\\(GUILD\\) compile")
>> + (string-append "$(GUILD) compile
>> --target="

[...]

Toggle quote (3 lines)
> Is there anything I can do as the author of guile-netlink to allow
> cross-compilation?

Yes, please! Pass ‘--target=$(HOST)’ to ‘guild compile’. See for
example how guile-zstd does it.

Thanks,
Ludo’.
L
L
Ludovic Courtès wrote on 29 Oct 2021 23:43
(name . Julien Lepiller)(address . julien@lepiller.eu)(address . 51440@debbugs.gnu.org)
87zgqrwlqx.fsf_-_@gnu.org
Hi!

Julien Lepiller <julien@lepiller.eu> skribis:

Toggle quote (32 lines)
> A few comments on the documentation below.
>
> Le Wed, 27 Oct 2021 16:02:42 +0200,
> Ludovic Courtès <ludo@gnu.org> a écrit :
>
>> @lisp
>> -(static-networking-service "eno1" "192.168.1.82"
>> - #:gateway "192.168.1.2"
>> - #:name-servers '("192.168.1.2"))
>> +;; Network configuration for one NIC, IPv4 + IPv6.
>> +(static-networking
>> + (addresses (list (network-address
>> + (device "eno1")
>> + (value "10.0.2.15/24"))
>> + (network-address
>> + (device "eno1")
>> + (value "2001:123:4567:101::1"))))
>> + (routes (list (network-route
>> + (destination "default")
>> + (gateway "10.0.2.2"))
>> + (network-route
>> + (destination "default")
>> + (gateway "2020:321:4567:42::1"))))
>> + (name-servers '("10.0.2.3")))
>> @end lisp
>
> I don't know if you tested that, but I think this is not routable
> because the IPv6 network doesn't have a netmask, so I think it defaults
> to a /128 (one IP in the network), so the router is not on the local
> network. Many ISPs provide a /64 (when the provide IPv6), so maybe use
> that as the netmask?

No I didn’t test it, so yes: let’s add /64 above.

Toggle quote (8 lines)
>> +ip address add 10.0.2.15/24 dev eno1
>> +ip address add 2001:123:4567:101::1 dev eno1
>> +ip route add default via inet 10.0.2.2
>> +ip route add default via inet6 2020:321:4567:42::1
>> +@end example
>
> And so, change it here too.

Yes.

Toggle quote (13 lines)
>> +Run @command{man 8 ip} for more info. Venerable GNU/Linux users will
>> +certainly know how to do it with @command{ifconfig} and
>> @command{route}, +but we'll spare you that.
>> +
>> +The available fields of this data type are as follows:
>> +
>> +@table @asis
>> +@item @code{addresses}
>> +@itemx @code{links} (default: @code{'()})
>> +@itemx @code{links} (default: @code{'()})
>
> One of them should be routes, right?

Oops, yes.

Toggle quote (7 lines)
>> +@item @code{provision} (default: @code{#f})
>> +If true, this should be a list of symbols for the Shepherd service
>> +corresponding to this network configuration. When @code{#f},
>> +@code{'(networking)} or @code{'(loopback)} is used.
>
> Under which conditions is it 'loopback instead of 'networking?

Hmm that part is wrong: #f is equivalent to (networking) in practice.
I’ll fix that.

Toggle quote (2 lines)
> The rest of the manual changes look good :)

You mentioned on IRC veth pairs as an example use of links. Could you
formalize it for inclusion as an example?

Thanks for the careful review!

Ludo’.
L
L
Ludovic Courtès wrote on 29 Oct 2021 23:44
(name . Julien Lepiller)(address . julien@lepiller.eu)(address . 51440@debbugs.gnu.org)
87v91fwlol.fsf_-_@gnu.org
Julien Lepiller <julien@lepiller.eu> skribis:

Toggle quote (2 lines)
> Looks good at first glance. I noticed a few typos in the manual, so I'll send you more details after I read it more carefully. I'll try that on my hardware, although again I'm not sure how I can run reconfigure from my checkout exactly? (Where do I use sudo, and what options do I need)

To reconfigure from a checkout, you can run:

sudo -E ./pre-inst-env guix system reconfigure …

where ‘-E’ tells sudo to preserve notably GUILE_LOAD_PATH & co., such
that Guile-Gcrypt and the other dependencies are found.

HTH!

Ludo’.
D
D
David Aaron Fendley wrote on 3 Nov 2021 14:27
[PATCH 00/10] Declarative static networking interface
(address . 51440@debbugs.gnu.org)
20211103132704.GA24459@triconium.com
If I have:

(service static-networking-service-type
(list (static-networking
(addresses (list (network-address
(device "eno33559296")
(value "10.7.99.99/24"))
(network-address
(device "eno16780032")
(value "10.10.199.98/24"))))
(routes (list (network-route
(destination "default")
(gateway "10.10.199.1"))
(network-route
(destination "192.168.0.1/32")
(gateway "10.10.199.1"))))
(name-servers '("10.10.199.17" "10.10.101.2")))))

After reconfigure and restart of the networking service, no routes
listed are created. Only the standard routes for each network:

> ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 127.0.0.1/0 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno16780032: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:98:d1:9f brd ff:ff:ff:ff:ff:ff
inet 10.10.199.98/24 scope global eno16780032
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe98:d19f/64 scope link
valid_lft forever preferred_lft forever
3: eno33559296: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:98:37:c2 brd ff:ff:ff:ff:ff:ff
inet 10.7.99.99/24 scope global eno33559296
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe98:37c2/64 scope link
valid_lft forever preferred_lft forever


> ip r
10.7.99.0/24 dev eno33559296 proto kernel scope link src 10.7.99.99
10.10.199.0/24 dev eno16780032 proto kernel scope link src 10.10.199.98


If I then change the config to:

(service static-networking-service-type
(list (static-networking
(addresses (list (network-address
(device "eno33559296")
(value "10.0.7.15/24"))
(network-address
(device "eno16780032")
(value "10.10.2.15/24"))))
(routes (list (network-route
(destination "default")
(gateway "10.0.2.2"))))
(name-servers '("10.0.2.3")))))



After reconfigure and restart of the networking service, routes
specified are still not created, and the addresses and routes are
appended:

> ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 127.0.0.1/0 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno16780032: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:98:d1:9f brd ff:ff:ff:ff:ff:ff
inet 10.10.199.98/24 scope global eno16780032
valid_lft forever preferred_lft forever
inet 10.10.2.15/24 scope global eno16780032
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe98:d19f/64 scope link
valid_lft forever preferred_lft forever
3: eno33559296: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:98:37:c2 brd ff:ff:ff:ff:ff:ff
inet 10.7.99.99/24 scope global eno33559296
valid_lft forever preferred_lft forever
inet 10.0.7.15/24 scope global eno33559296
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe98:37c2/64 scope link
valid_lft forever preferred_lft forever

> ip r

10.0.7.0/24 dev eno33559296 proto kernel scope link src 10.0.7.15
10.7.99.0/24 dev eno33559296 proto kernel scope link src 10.7.99.99
10.10.2.0/24 dev eno16780032 proto kernel scope link src 10.10.2.15
10.10.199.0/24 dev eno16780032 proto kernel scope link src 10.10.199.98


Expectation:

Routes declared would be added and standard network routes would be
removed if no longer relevant.


Environment:

These ten patches were applied on top of:

7af3b822178782d6598865e1d6a780a756dd0cb3


> guix describe
Generation 2 Nov 02 2021 13:37:58 (current)
guix 8d02b0d
branch: master
commit: 8d02b0d46cfc27b905f9276760aefacf518ae4f7
L
L
Ludovic Courtès wrote on 11 Nov 2021 23:08
(name . David Aaron Fendley)(address . tricon@triconium.com)(address . 51440@debbugs.gnu.org)
878rxufiqg.fsf_-_@gnu.org
Hi David,

David Aaron Fendley <tricon@triconium.com> skribis:

Toggle quote (21 lines)
> If I have:
>
> (service static-networking-service-type
> (list (static-networking
> (addresses (list (network-address
> (device "eno33559296")
> (value "10.7.99.99/24"))
> (network-address
> (device "eno16780032")
> (value "10.10.199.98/24"))))
> (routes (list (network-route
> (destination "default")
> (gateway "10.10.199.1"))
> (network-route
> (destination "192.168.0.1/32")
> (gateway "10.10.199.1"))))
> (name-servers '("10.10.199.17" "10.10.101.2")))))
>
> After reconfigure and restart of the networking service, no routes
> listed are created. Only the standard routes for each network:

Hmm right, I need to investigate this one some more. Apparently the
‘route-add’ call leads to “Network is unreachable”.

[...]

Toggle quote (21 lines)
> If I then change the config to:
>
> (service static-networking-service-type
> (list (static-networking
> (addresses (list (network-address
> (device "eno33559296")
> (value "10.0.7.15/24"))
> (network-address
> (device "eno16780032")
> (value "10.10.2.15/24"))))
> (routes (list (network-route
> (destination "default")
> (gateway "10.0.2.2"))))
> (name-servers '("10.0.2.3")))))
>
>
>
> After reconfigure and restart of the networking service, routes
> specified are still not created, and the addresses and routes are
> appended:

This one is fixed by the patch below: the ‘stop’ method of the service
would not actually load the “tear-down-network” file, oops!

Thanks a lot for testing and reporting!

To be continued…

Ludo’.
Toggle diff (37 lines)
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 66683f153f..3123122200 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -2511,7 +2511,7 @@ (define network-set-up/linux
                                 addresses)
                         #$@(map (match-lambda
                                   (($ <network-link> name type arguments)
-                                   #~(link-add #:device #$name #$type
+                                   #~(link-add #$name #$type
                                                #:type-args '#$arguments)))
                                 links)
                         #$@(map (lambda (route)
@@ -2530,7 +2530,7 @@ (define network-set-up/linux
 (define network-tear-down/linux
   (match-lambda
     (($ <static-networking> addresses links routes)
-     (scheme-file "set-up-network"
+     (scheme-file "tear-down-network"
                   (with-extensions (list guile-netlink)
                     #~(begin
                         (use-modules (ip addr) (ip link) (ip route))
@@ -2579,10 +2579,10 @@ (define (static-networking-shepherd-service config)
                                  (network-set-up/hurd config))))))
         (stop #~(lambda _
                   ;; Return #f is successfully stopped.
-                  #$(let-system (system target)
-                      (if (string-contains (or target system) "-linux")
-                          (network-tear-down/linux config)
-                          (network-tear-down/hurd config)))))
+                  (load #$(let-system (system target)
+                            (if (string-contains (or target system) "-linux")
+                                (network-tear-down/linux config)
+                                (network-tear-down/hurd config))))))
         (respawn? #f))))))
 
 (define (static-networking-shepherd-services networks)
L
L
Ludovic Courtès wrote on 14 Nov 2021 21:52
(name . David Aaron Fendley)(address . tricon@triconium.com)(address . 51440@debbugs.gnu.org)
8735nya29h.fsf_-_@gnu.org
Ludovic Courtès <ludo@gnu.org> skribis:

Toggle quote (26 lines)
> David Aaron Fendley <tricon@triconium.com> skribis:
>
>> If I have:
>>
>> (service static-networking-service-type
>> (list (static-networking
>> (addresses (list (network-address
>> (device "eno33559296")
>> (value "10.7.99.99/24"))
>> (network-address
>> (device "eno16780032")
>> (value "10.10.199.98/24"))))
>> (routes (list (network-route
>> (destination "default")
>> (gateway "10.10.199.1"))
>> (network-route
>> (destination "192.168.0.1/32")
>> (gateway "10.10.199.1"))))
>> (name-servers '("10.10.199.17" "10.10.101.2")))))
>>
>> After reconfigure and restart of the networking service, no routes
>> listed are created. Only the standard routes for each network:
>
> Hmm right, I need to investigate this one some more. Apparently the
> ‘route-add’ call leads to “Network is unreachable”.

Julien has just fixed that:


Hopefully we’ll have a new Guile-Netlink release soon with this fix.
:-)

Ludo’.
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 00/10] Declarative static networking interface
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-1-ludo@gnu.org
Hi!

Changes since v1:

• ‘herd stop networking’ fixed, as reported by David Aaron
Fendley.

• Guile-Netlink cross-compilation simplified thanks to changes
in Guile-Netlink 1.1.

• ‘provision’ field of <static-networking> defaults to
'(networking), as suggested by Julien.

• “network-tear-down” script wraps calls in ‘false-if-netlink-error’
to go as far as possible.

• Documentation fixed as suggested by Julien.

Thoughts? Test reports? :-)

Note: It requires Guile-Netlink 1.1 as added in
46432cceebe392a1744980f370a48ef73afbac2c (it fixes another issue
David reported earlier.)

Ludo’.

Ludovic Courtès (10):
tests: Add 'static-networking' test.
tests: openvswitch: Check whether ovs0 is up.
doc: Add new "Networking Setup" node for the main setup options.
gnu: guile-netlink: Allow cross-compilation.
services: static-networking: Use Guile-Netlink on GNU/Linux.
services: secret-service: Turn into a Shepherd service.
services: static-networking: Change interface to mimic netlink.
services: Define '%qemu-static-networking'.
services: Define '%loopback-static-networking'.
tests: Replace uses of deprecated 'static-networking-service'.

doc/guix.texi | 504 ++++++++++++++++++++++----------
gnu/build/hurd-boot.scm | 10 +-
gnu/build/secret-service.scm | 17 +-
gnu/packages/guile-xyz.scm | 3 +-
gnu/services/base.scm | 406 +++++++++++++++++++------
gnu/services/virtualization.scm | 45 ++-
gnu/system/hurd.scm | 12 +-
gnu/system/install.scm | 5 +-
gnu/tests/ganeti.scm | 7 +-
gnu/tests/networking.scm | 141 ++++++++-
10 files changed, 855 insertions(+), 295 deletions(-)


base-commit: 21332f3b8cb8f407a89cdfe7d0460a9947675872
--
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 02/10] tests: openvswitch: Check whether ovs0 is up.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-3-ludo@gnu.org
* gnu/tests/networking.scm (run-openvswitch-test)["ovs0 is up"]: New test.
---
gnu/tests/networking.scm | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

Toggle diff (43 lines)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 5da1c91da6..131428c128 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -286,12 +286,15 @@ (define %openvswitch-os
 (define (run-openvswitch-test)
   (define os
     (marionette-operating-system %openvswitch-os
-                                 #:imported-modules '((gnu services herd))))
+                                 #:imported-modules '((gnu services herd)
+                                                      (guix build syscalls))))
 
   (define test
-    (with-imported-modules '((gnu build marionette))
+    (with-imported-modules '((gnu build marionette)
+                             (guix build syscalls))
       #~(begin
           (use-modules (gnu build marionette)
+                       (guix build syscalls)
                        (ice-9 popen)
                        (ice-9 rdelim)
                        (srfi srfi-64))
@@ -339,6 +342,18 @@ (define marionette
                        (current-services))))
              marionette))
 
+          (test-equal "ovs0 is up"
+            IFF_UP
+            (marionette-eval
+             '(begin
+                (use-modules (guix build syscalls))
+
+                (let* ((sock  (socket AF_INET SOCK_STREAM 0))
+                       (flags (network-interface-flags sock "ovs0")))
+                  (close-port sock)
+                  (logand flags IFF_UP)))
+             marionette))
+
           (test-end)
           (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
 
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 03/10] doc: Add new "Networking Setup" node for the main setup options.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-4-ludo@gnu.org
This should make it easier to find how to get started setting up
networking.

* doc/guix.texi (Networking Setup): New section.
(Networking Services): Remove 'static-networking-service',
'dhcp-client-service-type', 'network-manager-service-type',
'connman-service-type', 'wicd-service', 'modem-manager-service-type',
'usb-modeswitch-service-type', and 'wpa-supplicant-service-type'.
---
doc/guix.texi | 289 ++++++++++++++++++++++++++++----------------------
1 file changed, 160 insertions(+), 129 deletions(-)

Toggle diff (342 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index ea0c51d11a..399664b910 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -342,7 +342,8 @@ Services
 * Base Services::               Essential system services.
 * Scheduled Job Execution::     The mcron service.
 * Log Rotation::                The rottlog service.
-* Networking Services::         Network setup, SSH daemon, etc.
+* Networking Setup::            Setting up network interfaces.
+* Networking Services::         Firewall, SSH daemon, etc.
 * Unattended Upgrades::         Automated system upgrades.
 * X Window::                    Graphical display.
 * Printing Services::           Local and remote printer support.
@@ -15534,7 +15535,8 @@ declaration.
 * Base Services::               Essential system services.
 * Scheduled Job Execution::     The mcron service.
 * Log Rotation::                The rottlog service.
-* Networking Services::         Network setup, SSH daemon, etc.
+* Networking Setup::            Setting up network interfaces.
+* Networking Services::         Firewall, SSH daemon, etc.
 * Unattended Upgrades::         Automated system upgrades.
 * X Window::                    Graphical display.
 * Printing Services::           Local and remote printer support.
@@ -16756,63 +16758,26 @@ The list of syslog-controlled files to be rotated.  By default it is:
 "/var/log/maillog")}.
 @end defvr
 
-@node Networking Services
-@subsection Networking Services
+@node Networking Setup
+@subsection Networking Setup
 
-The @code{(gnu services networking)} module provides services to configure
-the network interface.
+The @code{(gnu services networking)} module provides services to
+configure network interfaces and set up networking on your machine.
+Those services provide different ways for you to set up your machine: by
+declaring a static network configuration, by running a Dynamic Host
+Configuration Protocol (DHCP) client, or by running daemons such as
+NetworkManager and Connman that automate the whole process,
+automatically adapt to connectivity changes, and provide a high-level
+user interface.
 
-@cindex DHCP, networking service
-@defvr {Scheme Variable} dhcp-client-service-type
-This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
-Protocol (DHCP) client, on all the non-loopback network interfaces.  Its value
-is the DHCP client package to use, @code{isc-dhcp} by default.
-@end defvr
+On a laptop, NetworkManager and Connman are by far the most convenient
+options, which is why the default desktop services include
+NetworkManager (@pxref{Desktop Services, @code{%desktop-services}}).
+For a server, or for a virtual machine or a container, static network
+configuration or a simple DHCP client are often more appropriate.
 
-@deffn {Scheme Procedure} dhcpd-service-type
-This type defines a service that runs a DHCP daemon.  To create a
-service of this type, you must supply a @code{<dhcpd-configuration>}.
-For example:
-
-@lisp
-(service dhcpd-service-type
-         (dhcpd-configuration
-          (config-file (local-file "my-dhcpd.conf"))
-          (interfaces '("enp0s25"))))
-@end lisp
-@end deffn
-
-@deftp {Data Type} dhcpd-configuration
-@table @asis
-@item @code{package} (default: @code{isc-dhcp})
-The package that provides the DHCP daemon.  This package is expected to
-provide the daemon at @file{sbin/dhcpd} relative to its output
-directory.  The default package is the
-@uref{https://www.isc.org/products/DHCP, ISC's DHCP server}.
-@item @code{config-file} (default: @code{#f})
-The configuration file to use.  This is required.  It will be passed to
-@code{dhcpd} via its @code{-cf} option.  This may be any ``file-like''
-object (@pxref{G-Expressions, file-like objects}).  See @code{man
-dhcpd.conf} for details on the configuration file syntax.
-@item @code{version} (default: @code{"4"})
-The DHCP version to use.  The ISC DHCP server supports the values ``4'',
-``6'', and ``4o6''.  These correspond to the @code{dhcpd} program
-options @code{-4}, @code{-6}, and @code{-4o6}.  See @code{man dhcpd} for
-details.
-@item @code{run-directory} (default: @code{"/run/dhcpd"})
-The run directory to use.  At service activation time, this directory
-will be created if it does not exist.
-@item @code{pid-file} (default: @code{"/run/dhcpd/dhcpd.pid"})
-The PID file to use.  This corresponds to the @code{-pf} option of
-@code{dhcpd}.  See @code{man dhcpd} for details.
-@item @code{interfaces} (default: @code{'()})
-The names of the network interfaces on which dhcpd should listen for
-broadcasts.  If this list is not empty, then its elements (which must be
-strings) will be appended to the @code{dhcpd} invocation when starting
-the daemon.  It may not be necessary to explicitly specify any
-interfaces here; see @code{man dhcpd} for details.
-@end table
-@end deftp
+This section describes the various network setup services available,
+starting with static network configuration.
 
 @defvr {Scheme Variable} static-networking-service-type
 This is the type for statically-configured network interfaces.
@@ -16842,81 +16807,13 @@ For example:
 @end lisp
 @end deffn
 
-@cindex wicd
-@cindex wireless
-@cindex WiFi
-@cindex network management
-@deffn {Scheme Procedure} wicd-service [#:wicd @var{wicd}]
-Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
-management daemon that aims to simplify wired and wireless networking.
-
-This service adds the @var{wicd} package to the global profile, providing
-several commands to interact with the daemon and configure networking:
-@command{wicd-client}, a graphical user interface, and the @command{wicd-cli}
-and @command{wicd-curses} user interfaces.
-@end deffn
-
-@cindex ModemManager
-
-@defvr {Scheme Variable} modem-manager-service-type
-This is the service type for the
-@uref{https://wiki.gnome.org/Projects/ModemManager, ModemManager}
-service.  The value for this service type is a
-@code{modem-manager-configuration} record.
-
-This service is part of @code{%desktop-services} (@pxref{Desktop
-Services}).
+@cindex DHCP, networking service
+@defvr {Scheme Variable} dhcp-client-service-type
+This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
+Protocol (DHCP) client, on all the non-loopback network interfaces.  Its value
+is the DHCP client package to use, @code{isc-dhcp} by default.
 @end defvr
 
-@deftp {Data Type} modem-manager-configuration
-Data type representing the configuration of ModemManager.
-
-@table @asis
-@item @code{modem-manager} (default: @code{modem-manager})
-The ModemManager package to use.
-
-@end table
-@end deftp
-
-@cindex USB_ModeSwitch
-@cindex Modeswitching
-
-@defvr {Scheme Variable} usb-modeswitch-service-type
-This is the service type for the
-@uref{https://www.draisberghof.de/usb_modeswitch/, USB_ModeSwitch}
-service.  The value for this service type is
-a @code{usb-modeswitch-configuration} record.
-
-When plugged in, some USB modems (and other USB devices) initially present
-themselves as a read-only storage medium and not as a modem.  They need to be
-@dfn{modeswitched} before they are usable.  The USB_ModeSwitch service type
-installs udev rules to automatically modeswitch these devices when they are
-plugged in.
-
-This service is part of @code{%desktop-services} (@pxref{Desktop
-Services}).
-@end defvr
-
-@deftp {Data Type} usb-modeswitch-configuration
-Data type representing the configuration of USB_ModeSwitch.
-
-@table @asis
-@item @code{usb-modeswitch} (default: @code{usb-modeswitch})
-The USB_ModeSwitch package providing the binaries for modeswitching.
-
-@item @code{usb-modeswitch-data} (default: @code{usb-modeswitch-data})
-The package providing the device data and udev rules file used by
-USB_ModeSwitch.
-
-@item @code{config-file} (default: @code{#~(string-append #$usb-modeswitch:dispatcher "/etc/usb_modeswitch.conf")})
-Which config file to use for the USB_ModeSwitch dispatcher.  By default the
-config file shipped with USB_ModeSwitch is used which disables logging to
-@file{/var/log} among other default settings.  If set to @code{#f}, no config
-file is used.
-
-@end table
-@end deftp
-
 @cindex NetworkManager
 
 @defvr {Scheme Variable} network-manager-service-type
@@ -17053,6 +16950,139 @@ List of additional command-line arguments to pass to the daemon.
 @end table
 @end deftp
 
+@cindex wicd
+@cindex wireless
+@cindex WiFi
+@cindex network management
+@deffn {Scheme Procedure} wicd-service [#:wicd @var{wicd}]
+Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network
+management daemon that aims to simplify wired and wireless networking.
+
+This service adds the @var{wicd} package to the global profile, providing
+several commands to interact with the daemon and configure networking:
+@command{wicd-client}, a graphical user interface, and the @command{wicd-cli}
+and @command{wicd-curses} user interfaces.
+@end deffn
+
+@cindex ModemManager
+Some networking devices such as modems require special care, and this is
+what the services below focus on.
+
+@defvr {Scheme Variable} modem-manager-service-type
+This is the service type for the
+@uref{https://wiki.gnome.org/Projects/ModemManager, ModemManager}
+service.  The value for this service type is a
+@code{modem-manager-configuration} record.
+
+This service is part of @code{%desktop-services} (@pxref{Desktop
+Services}).
+@end defvr
+
+@deftp {Data Type} modem-manager-configuration
+Data type representing the configuration of ModemManager.
+
+@table @asis
+@item @code{modem-manager} (default: @code{modem-manager})
+The ModemManager package to use.
+
+@end table
+@end deftp
+
+@cindex USB_ModeSwitch
+@cindex Modeswitching
+
+@defvr {Scheme Variable} usb-modeswitch-service-type
+This is the service type for the
+@uref{https://www.draisberghof.de/usb_modeswitch/, USB_ModeSwitch}
+service.  The value for this service type is
+a @code{usb-modeswitch-configuration} record.
+
+When plugged in, some USB modems (and other USB devices) initially present
+themselves as a read-only storage medium and not as a modem.  They need to be
+@dfn{modeswitched} before they are usable.  The USB_ModeSwitch service type
+installs udev rules to automatically modeswitch these devices when they are
+plugged in.
+
+This service is part of @code{%desktop-services} (@pxref{Desktop
+Services}).
+@end defvr
+
+@deftp {Data Type} usb-modeswitch-configuration
+Data type representing the configuration of USB_ModeSwitch.
+
+@table @asis
+@item @code{usb-modeswitch} (default: @code{usb-modeswitch})
+The USB_ModeSwitch package providing the binaries for modeswitching.
+
+@item @code{usb-modeswitch-data} (default: @code{usb-modeswitch-data})
+The package providing the device data and udev rules file used by
+USB_ModeSwitch.
+
+@item @code{config-file} (default: @code{#~(string-append #$usb-modeswitch:dispatcher "/etc/usb_modeswitch.conf")})
+Which config file to use for the USB_ModeSwitch dispatcher.  By default the
+config file shipped with USB_ModeSwitch is used which disables logging to
+@file{/var/log} among other default settings.  If set to @code{#f}, no config
+file is used.
+
+@end table
+@end deftp
+
+
+@node Networking Services
+@subsection Networking Services
+
+The @code{(gnu services networking)} module discussed in the previous
+section provides services for more advanced setups: providing a DHCP
+service for others to use, filtering packets with iptables or nftables,
+running a WiFi access point with @command{hostapd}, running the
+@command{inetd} ``superdaemon'', and more.  This section describes
+those.
+
+@deffn {Scheme Procedure} dhcpd-service-type
+This type defines a service that runs a DHCP daemon.  To create a
+service of this type, you must supply a @code{<dhcpd-configuration>}.
+For example:
+
+@lisp
+(service dhcpd-service-type
+         (dhcpd-configuration
+          (config-file (local-file "my-dhcpd.conf"))
+          (interfaces '("enp0s25"))))
+@end lisp
+@end deffn
+
+@deftp {Data Type} dhcpd-configuration
+@table @asis
+@item @code{package} (default: @code{isc-dhcp})
+The package that provides the DHCP daemon.  This package is expected to
+provide the daemon at @file{sbin/dhcpd} relative to its output
+directory.  The default package is the
+@uref{https://www.isc.org/products/DHCP, ISC's DHCP server}.
+@item @code{config-file} (default: @code{#f})
+The configuration file to use.  This is required.  It will be passed to
+@code{dhcpd} via its @code{-cf} option.  This may be any ``file-like''
+object (@pxref{G-Expressions, file-like objects}).  See @code{man
+dhcpd.conf} for details on the configuration file syntax.
+@item @code{version} (default: @code{"4"})
+The DHCP version to use.  The ISC DHCP server supports the values ``4'',
+``6'', and ``4o6''.  These correspond to the @code{dhcpd} program
+options @code{-4}, @code{-6}, and @code{-4o6}.  See @code{man dhcpd} for
+details.
+@item @code{run-directory} (default: @code{"/run/dhcpd"})
+The run directory to use.  At service activation time, this directory
+will be created if it does not exist.
+@item @code{pid-file} (default: @code{"/run/dhcpd/dhcpd.pid"})
+The PID file to use.  This corresponds to the @code{-pf} option of
+@code{dhcpd}.  See @code{man dhcpd} for details.
+@item @code{interfaces} (default: @code{'()})
+The names of the network interfaces on which dhcpd should listen for
+broadcasts.  If this list is not empty, then its elements (which must be
+strings) will be appended to the @code{dhcpd} invocation when starting
+the daemon.  It may not be necessary to explicitly specify any
+interfaces here; see @code{man dhcpd} for details.
+@end table
+@end deftp
+
 @cindex hostapd service, for Wi-Fi access points
 @cindex Wi-Fi access points, hostapd service
 @defvr {Scheme Variable} hostapd-service-type
@@ -17115,6 +17145,7 @@ network that can be seen on @code{wlan0}, by default.
 The service's value is a @code{hostapd-configuration} record.
 @end defvr
 
+
 @cindex iptables
 @defvr {Scheme Variable} iptables-service-type
 This is the service type to set up an iptables configuration.  iptables is a
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 01/10] tests: Add 'static-networking' test.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-2-ludo@gnu.org
* gnu/tests/networking.scm (run-static-networking-test): New procedure.
(%test-static-networking): New variable.
---
gnu/tests/networking.scm | 99 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 97 insertions(+), 2 deletions(-)

Toggle diff (119 lines)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 453e63f52d..5da1c91da6 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -4,6 +4,7 @@
 ;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
 ;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
 ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -37,8 +38,102 @@ (define-module (gnu tests networking)
   #:use-module (gnu packages guile)
   #:use-module (gnu services shepherd)
   #:use-module (ice-9 match)
-  #:export (%test-inetd %test-openvswitch %test-dhcpd %test-tor %test-iptables
-                        %test-ipfs))
+  #:export (%test-static-networking
+            %test-inetd
+            %test-openvswitch
+            %test-dhcpd
+            %test-tor
+            %test-iptables
+            %test-ipfs))
+
+
+;;;
+;;; Static networking.
+;;;
+
+(define (run-static-networking-test vm)
+  (define test
+    (with-imported-modules '((gnu build marionette)
+                             (guix build syscalls))
+      #~(begin
+          (use-modules (gnu build marionette)
+                       (guix build syscalls)
+                       (srfi srfi-64))
+
+          (define marionette
+            (make-marionette
+             '(#$vm "-nic" "user,model=virtio-net-pci")))
+
+          (mkdir #$output)
+          (chdir #$output)
+
+          (test-begin "static-networking")
+
+          (test-assert "service is up"
+            (marionette-eval
+             '(begin
+                (use-modules (gnu services herd))
+                (start-service 'networking))
+             marionette))
+
+          (test-assert "network interfaces"
+            (marionette-eval
+             '(begin
+                (use-modules (guix build syscalls))
+                (network-interface-names))
+             marionette))
+
+          (test-equal "address of eth0"
+            "10.0.2.15"
+            (marionette-eval
+             '(let* ((sock (socket AF_INET SOCK_STREAM 0))
+                     (addr (network-interface-address sock "eth0")))
+                (close-port sock)
+                (inet-ntop (sockaddr:fam addr) (sockaddr:addr addr)))
+             marionette))
+
+          (test-equal "netmask of eth0"
+            "255.255.255.0"
+            (marionette-eval
+             '(let* ((sock (socket AF_INET SOCK_STREAM 0))
+                     (mask (network-interface-netmask sock "eth0")))
+                (close-port sock)
+                (inet-ntop (sockaddr:fam mask) (sockaddr:addr mask)))
+             marionette))
+
+          (test-equal "eth0 is up"
+            IFF_UP
+            (marionette-eval
+             '(let* ((sock  (socket AF_INET SOCK_STREAM 0))
+                     (flags (network-interface-flags sock "eth0")))
+                (logand flags IFF_UP))
+             marionette))
+
+          (test-end)
+
+          (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
+
+  (gexp->derivation "static-networking" test))
+
+(define %test-static-networking
+  (system-test
+   (name "static-networking")
+   (description "Test the 'static-networking' service.")
+   (value
+    (let ((os (marionette-operating-system
+               (simple-operating-system
+                (static-networking-service "eth0" "10.0.2.15"
+                                           #:netmask "255.255.255.0"
+                                           #:gateway "10.0.2.2"
+                                           #:name-servers '("10.0.2.2")))
+               #:imported-modules '((gnu services herd)
+                                    (guix combinators)))))
+      (run-static-networking-test (virtual-machine os))))))
+
+
+;;;
+;;; Inetd.
+;;;
 
 (define %inetd-os
   ;; Operating system with 2 inetd services.
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 08/10] services: Define '%qemu-static-networking'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-9-ludo@gnu.org
* gnu/services/base.scm (%qemu-static-networking): New variable.
* gnu/system/hurd.scm (%base-services/hurd): Use it.
* doc/guix.texi (Networking Setup): Document it.
---
doc/guix.texi | 8 ++++++++
gnu/services/base.scm | 16 ++++++++++++++++
gnu/system/hurd.scm | 21 ++++++---------------
3 files changed, 30 insertions(+), 15 deletions(-)

Toggle diff (87 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 439ef28e96..85e76991d9 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16940,6 +16940,14 @@ List of arguments for this type of link.
 @end table
 @end deftp
 
+@cindex networking, with QEMU
+@cindex QEMU, networking
+@defvr {Scheme Variable} %qemu-static-networking
+This is the @code{static-networking} record representing network setup
+when using QEMU's user-mode network stack on @code{eth0} (@pxref{Using
+the user mode network stack,,, QEMU, QEMU Documentation}).
+@end defvr
+
 @cindex DHCP, networking service
 @defvr {Scheme Variable} dhcp-client-service-type
 This is the type of services that run @var{dhcp}, a Dynamic Host Configuration
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 112c6ab065..e78add4e20 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -113,6 +113,8 @@ (define-module (gnu services base)
             static-networking-service
             static-networking-service-type
 
+            %qemu-static-networking
+
             udev-configuration
             udev-configuration?
             udev-configuration-rules
@@ -2669,6 +2671,20 @@ (define-deprecated (static-networking-service interface ip
                          (provision (or provision '(networking)))
                          (name-servers name-servers)))))
 
+(define %qemu-static-networking
+  ;; Networking configuration for QEMU's user-mode network stack (info "(QEMU)
+  ;; Using the user mode network stack").
+  (static-networking
+   (addresses (list (network-address
+                     (device "eth0")
+                     (value "10.0.2.15/24"))))
+   (routes (list (network-route
+                  (destination "default")
+                  (gateway "10.0.2.2"))))
+   (requirement '())
+   (provision '(networking))
+   (name-servers '("10.0.2.3"))))
+
 
 (define %base-services
   ;; Convenience variable holding the basic services.
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index 0e73ca0d99..ec8484d746 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -86,21 +86,12 @@ (define %base-services/hurd
                                 (value "127.0.0.1"))))
                         (requirement '())
                         (provision '(loopback)))
-                       (static-networking
-                        (addresses
-                         ;; The default QEMU guest address.  To get "eth0",
-                         ;; you need QEMU to emulate a device for which Mach
-                         ;; has an in-kernel driver, for instance with:
-                         ;; --device rtl8139,netdev=net0 --netdev user,id=net0
-                         (list (network-address
-                                (device "eth0")
-                                (value "10.0.2.15/24"))))
-                        (routes
-                         (list (network-route
-                                (destination "default")
-                                (gateway "10.0.2.2"))))
-                        (provision '(networking))
-                        (name-servers '("10.0.2.3")))))
+
+                       ;; QEMU user-mode networking.  To get "eth0", you need
+                       ;; QEMU to emulate a device for which Mach has an
+                       ;; in-kernel driver, for instance with:
+                       ;; --device rtl8139,netdev=net0 --netdev user,id=net0
+                       %qemu-static-networking))
         (syslog-service)
         (service guix-service-type
                  (guix-configuration
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 10/10] tests: Replace uses of deprecated 'static-networking-service'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-11-ludo@gnu.org
* gnu/tests/ganeti.scm (%ganeti-os): Replace call to
'static-networking-service' by instantiating
STATIC-NETWORKING-SERVICE-TYPE.
* gnu/tests/networking.scm (%test-static-networking)
(%openvswitch-os, %dhcpd-os): Likewise.
---
gnu/tests/ganeti.scm | 7 ++-----
gnu/tests/networking.scm | 29 ++++++++++++++++++-----------
2 files changed, 20 insertions(+), 16 deletions(-)

Toggle diff (74 lines)
diff --git a/gnu/tests/ganeti.scm b/gnu/tests/ganeti.scm
index 5ac2fd48dd..c29b885a5e 100644
--- a/gnu/tests/ganeti.scm
+++ b/gnu/tests/ganeti.scm
@@ -59,11 +59,8 @@ (define %ganeti-os
     (packages (append (list ganeti-instance-debootstrap ganeti-instance-guix)
                       %base-packages))
     (services
-     (append (list (static-networking-service "eth0" "10.0.2.15"
-                                              #:netmask "255.255.255.0"
-                                              #:gateway "10.0.2.2"
-                                              #:name-servers '("10.0.2.3"))
-
+     (append (list (service static-networking-service-type
+                            (list %qemu-static-networking))
                    (service openssh-service-type
                             (openssh-configuration
                              (permit-root-login 'prohibit-password)))
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index c66af279f2..246e0a15fa 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -122,10 +122,8 @@ (define %test-static-networking
    (value
     (let ((os (marionette-operating-system
                (simple-operating-system
-                (static-networking-service "eth0" "10.0.2.15"
-                                           #:netmask "255.255.255.0"
-                                           #:gateway "10.0.2.2"
-                                           #:name-servers '("10.0.2.2")))
+                (service static-networking-service-type
+                         (list %qemu-static-networking)))
                #:imported-modules '((gnu services herd)
                                     (guix combinators)))))
       (run-static-networking-test (virtual-machine os))))))
@@ -275,9 +273,13 @@ (define openvswitch-configuration-service
 (define %openvswitch-os
   (operating-system
     (inherit (simple-operating-system
-              (static-networking-service "ovs0" "10.1.1.1"
-                                         #:netmask "255.255.255.252"
-                                         #:requirement '(openvswitch-configuration))
+              (simple-service 'openswitch-networking
+                              static-networking-service-type
+                              (list (static-networking
+                                     (addresses (list (network-address
+                                                       (value "10.1.1.1/24")
+                                                       (device "ovs0"))))
+                                     (requirement '(openvswitch-configuration)))))
               (service openvswitch-service-type)
               openvswitch-configuration-service))
     ;; Ensure the interface name does not change depending on the driver.
@@ -392,10 +394,15 @@ (define dhcpd-v4-configuration
 
 (define %dhcpd-os
   (simple-operating-system
-   (static-networking-service "ens3" "192.168.1.4"
-                              #:netmask "255.255.255.0"
-                              #:gateway "192.168.1.1"
-                              #:name-servers '("192.168.1.2" "192.168.1.3"))
+   (service static-networking-service-type
+            (list (static-networking
+                   (addresses (list (network-address
+                                     (value "192.168.1.4/24")
+                                     (device "ens3"))))
+                   (routes (list (network-route
+                                  (destination "default")
+                                  (gateway "192.168.1.1"))))
+                   (name-servers '("192.168.1.2" "192.168.1.3")))))
    (service dhcpd-service-type dhcpd-v4-configuration)))
 
 (define (run-dhcpd-test)
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 07/10] services: static-networking: Change interface to mimic netlink.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-8-ludo@gnu.org
* gnu/services/base.scm (<static-networking>)[interface, ip, netmask]
[gateway]: Remove.
[addresses, links, routes]: New fields.
[requirement]: Default to '(udev).
(<network-address>, <network-link>, <network-route>): New record types.
(ensure-no-separate-netmask, %ensure-no-separate-netmask): Remove.
(ipv6-address?, cidr->netmask, ip+netmask->cidr)
(network-set-up/hurd, network-tear-down/hurd)
(network-set-up/linux, network-tear-down/linux)
(static-networking->hurd-pfinet-options): New procedures.
(static-networking-shepherd-service): New procedure.
(static-networking-shepherd-services): Rewrite in terms of the above.
(static-networking-service): Deprecate. Adjust to new
'static-networking' API.
(%base-services): Likewise.
* gnu/system/install.scm (%installation-services): Likewise.
* gnu/system/hurd.scm (%base-services/hurd): Likewise, and separate
'loopback' from 'networking'.
* gnu/build/hurd-boot.scm (set-hurd-device-translators): Remove
"servers/socket/2".
* gnu/tests/networking.scm (run-openvswitch-test)["networking has
started on ovs0"]: Check for 'networking instead of 'networking-ovs0,
which is no longer provided.
* doc/guix.texi (Networking Setup): Document the new interface. Remove
documentation of 'static-networking-service'.
(Virtualization Services): Change Ganeti example to use the new
interface.
---
doc/guix.texi | 190 ++++++++++++++---
gnu/build/hurd-boot.scm | 10 +-
gnu/services/base.scm | 425 +++++++++++++++++++++++++++------------
gnu/system/hurd.scm | 27 ++-
gnu/system/install.scm | 11 +-
gnu/tests/networking.scm | 2 +-
6 files changed, 494 insertions(+), 171 deletions(-)

Toggle diff (820 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 399664b910..439ef28e96 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16780,32 +16780,165 @@ This section describes the various network setup services available,
 starting with static network configuration.
 
 @defvr {Scheme Variable} static-networking-service-type
-This is the type for statically-configured network interfaces.
-@c TODO Document <static-networking> data structures.
+This is the type for statically-configured network interfaces.  Its
+value must be a list of @code{static-networking} records.  Each of them
+declares a set of @dfn{addresses}, @dfn{routes}, and @dfn{links}, as
+show below.
+
+@cindex network interface controller (NIC)
+@cindex NIC, networking interface controller
+Here is the simplest configuration, with only one network interface
+controller (NIC) and only IPv4 connectivity:
+
+@example
+;; Static networking for one NIC, IPv4-only.
+(service static-networking-service-type
+         (list (static-networking
+                (addresses
+                 (list (network-address
+                        (device "eno1")
+                        (value "10.0.2.15/24"))))
+                (routes
+                 (list (network-route
+                        (destination "default")
+                        (gateway "10.0.2.2"))))
+                (name-servers '("10.0.2.3")))))
+@end example
+
+The snippet above can be added to the @code{services} field of your
+operating system configuration (@pxref{Using the Configuration System}).
+It will configure your machine to have 10.0.2.15 as its IP address, with
+a 24-bit netmask for the local network---meaning that any 10.0.2.@var{x}
+address is on the local area network (LAN).  Traffic to addresses
+outside the local network is routed @i{via} 10.0.2.2.  Host names are
+resolved by sending domain name system (DNS) queries to 10.0.2.3.
 @end defvr
 
-@deffn {Scheme Procedure} static-networking-service @var{interface} @var{ip} @
-       [#:netmask #f] [#:gateway #f] [#:name-servers @code{'()}] @
-       [#:requirement @code{'(udev)}]
-Return a service that starts @var{interface} with address @var{ip}.  If
-@var{netmask} is true, use it as the network mask.  If @var{gateway} is true,
-it must be a string specifying the default network gateway.  @var{requirement}
-can be used to declare a dependency on another service before configuring the
-interface.
+@deftp {Data Type} static-networking
+This is the data type representing a static network configuration.
 
-This procedure can be called several times, one for each network
-interface of interest.  Behind the scenes what it does is extend
-@code{static-networking-service-type} with additional network interfaces
-to handle.
-
-For example:
+As an example, here is how you would declare the configuration of a
+machine with a single network interface controller (NIC) available as
+@code{eno1}, and with one IPv4 and one IPv6 address:
 
 @lisp
-(static-networking-service "eno1" "192.168.1.82"
-                           #:gateway "192.168.1.2"
-                           #:name-servers '("192.168.1.2"))
+;; Network configuration for one NIC, IPv4 + IPv6.
+(static-networking
+ (addresses (list (network-address
+                   (device "eno1")
+                   (value "10.0.2.15/24"))
+                  (network-address
+                   (device "eno1")
+                   (value "2001:123:4567:101::1/64"))))
+ (routes (list (network-route
+                (destination "default")
+                (gateway "10.0.2.2"))
+               (network-route
+                (destination "default")
+                (gateway "2020:321:4567:42::1"))))
+ (name-servers '("10.0.2.3")))
 @end lisp
-@end deffn
+
+If you are familiar with the @command{ip} command of the
+@uref{https://wiki.linuxfoundation.org/networking/iproute2,
+@code{iproute2} package} found on Linux-based systems, the declaration
+above is equivalent to typing:
+
+@example
+ip address add 10.0.2.15/24 dev eno1
+ip address add 2001:123:4567:101::1/64 dev eno1
+ip route add default via inet 10.0.2.2
+ip route add default via inet6 2020:321:4567:42::1
+@end example
+
+Run @command{man 8 ip} for more info.  Venerable GNU/Linux users will
+certainly know how to do it with @command{ifconfig} and @command{route},
+but we'll spare you that.
+
+The available fields of this data type are as follows:
+
+@table @asis
+@item @code{addresses}
+@itemx @code{links} (default: @code{'()})
+@itemx @code{routes} (default: @code{'()})
+The list of @code{network-address}, @code{network-link}, and
+@code{network-route} records for this network (see below).
+
+@item @code{name-servers} (default: @code{'()})
+The list of IP addresses (strings) of domain name servers.  These IP
+addresses go to @file{/etc/resolv.conf}.
+
+@item @code{provision} (default: @code{'(networking)})
+If true, this should be a list of symbols for the Shepherd service
+corresponding to this network configuration.
+
+@item @code{requirement} (default @code{'()})
+The list of Shepherd services depended on.
+@end table
+@end deftp
+
+@deftp {Data Type} network-address
+This is the data type representing the IP address of a network
+interface.
+
+@table @code
+@item device
+The name of the network interface for this address---e.g.,
+@code{"eno1"}.
+
+@item value
+The actual IP address and network mask, in
+@uref{https://en.wikipedia.org/wiki/CIDR#CIDR_notation, @acronym{CIDR,
+Classless Inter-Domain Routing} notation}, as a string.
+
+For example, @code{"10.0.2.15/24"} denotes IPv4 address 10.0.2.15 on a
+24-bit sub-network---all 10.0.2.@var{x} addresses are on the same local
+network.
+
+@item ipv6?
+Whether @code{value} denotes an IPv6 address.  By default this is
+automatically determined.
+@end table
+@end deftp
+
+@deftp {Data Type} network-route
+This is the data type representing a network route.
+
+@table @asis
+@item @code{destination}
+The route destination (a string), either an IP address or
+@code{"default"} to denote the default route.
+
+@item @code{source} (default: @code{#f})
+The route source.
+
+@item @code{device} (default: @code{#f})
+The device used for this route---e.g., @code{"eno2"}.
+
+@item @code{ipv6?} (default: auto)
+Whether this is an IPv6 route.  By default this is automatically
+determined based on @code{destination} or @code{gateway}.
+
+@item @code{gateway} (default: @code{#f})
+IP address (a string) through which traffic is routed.
+@end table
+@end deftp
+
+@deftp {Data Type} network-link
+Data type for a network link (@pxref{Link,,, guile-netlink,
+Guile-Netlink Manual}).
+
+@table @code
+@item name
+The name of the link---e.g., @code{"v0p0"}.
+
+@item type
+A symbol denoting the type of the link---e.g., @code{'veth}.
+
+@item arguments
+List of arguments for this type of link.
+@end table
+@end deftp
 
 @cindex DHCP, networking service
 @defvr {Scheme Variable} dhcp-client-service-type
@@ -30371,11 +30504,18 @@ cluster node that supports multiple storage backends, and installs the
                            "ganeti-instance-guix" "ganeti-instance-debootstrap"))
                     %base-packages))
   (services
-   (append (list (static-networking-service "eth0" "192.168.1.201"
-                                            #:netmask "255.255.255.0"
-                                            #:gateway "192.168.1.254"
-                                            #:name-servers '("192.168.1.252"
-                                                             "192.168.1.253"))
+   (append (list (service static-networking-service-type
+                          (list (static-networking
+                                 (addresses
+                                  (list (network-address
+                                         (device "eth0")
+                                         (value "192.168.1.201/24"))))
+                                 (routes
+                                  (list (network-route
+                                         (destination "default")
+                                         (gateway "192.168.1.254"))))
+                                 (name-servers '("192.168.1.252"
+                                                 "192.168.1.253")))))
 
                  ;; Ganeti uses SSH to communicate between nodes.
                  (service openssh-service-type
diff --git a/gnu/build/hurd-boot.scm b/gnu/build/hurd-boot.scm
index 8b27995438..ac36bd17d4 100644
--- a/gnu/build/hurd-boot.scm
+++ b/gnu/build/hurd-boot.scm
@@ -185,13 +185,9 @@ (define servers
       ("servers/crash-suspend"   ("/hurd/crash" "--suspend"))
       ("servers/password"        ("/hurd/password"))
       ("servers/socket/1"        ("/hurd/pflocal"))
-      ("servers/socket/2"        ("/hurd/pfinet"
-                                  "--interface" "eth0"
-                                  "--address"
-                                  "10.0.2.15" ;the default QEMU guest IP
-                                  "--netmask" "255.255.255.0"
-                                  "--gateway" "10.0.2.2"
-                                  "--ipv6" "/servers/socket/26"))
+      ;; /servers/socket/2 and /26 are created by 'static-networking-service'.
+      ;; XXX: Spawn pfinet without arguments on these nodes so that a DHCP
+      ;; client has someone to talk to?
       ("proc"                    ("/hurd/procfs" "--stat-mode=444"))))
 
   (define devices
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index d5ee03bbbd..112c6ab065 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -35,6 +35,8 @@
 (define-module (gnu services base)
   #:use-module (guix store)
   #:use-module (guix deprecation)
+  #:autoload   (guix diagnostics) (warning)
+  #:autoload   (guix i18n) (G_)
   #:use-module (gnu services)
   #:use-module (gnu services admin)
   #:use-module (gnu services shepherd)
@@ -54,6 +56,7 @@ (define-module (gnu services base)
   #:use-module ((gnu packages base)
                 #:select (coreutils glibc glibc-utf8-locales))
   #:autoload   (gnu packages guile-xyz) (guile-netlink)
+  #:autoload   (gnu packages hurd) (hurd)
   #:use-module (gnu packages package-management)
   #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
   #:use-module (gnu packages linux)
@@ -81,14 +84,32 @@ (define-module (gnu services base)
             virtual-terminal-service-type
 
             static-networking
-
             static-networking?
-            static-networking-interface
-            static-networking-ip
-            static-networking-netmask
-            static-networking-gateway
+            static-networking-addresses
+            static-networking-links
+            static-networking-routes
             static-networking-requirement
 
+            network-address
+            network-address?
+            network-address-device
+            network-address-value
+            network-address-ipv6?
+
+            network-link
+            network-link?
+            network-link-name
+            network-link-type
+            network-link-arguments
+
+            network-route
+            network-route?
+            network-route-destination
+            network-route-source
+            network-route-device
+            network-route-ipv6?
+            network-route-gateway
+
             static-networking-service
             static-networking-service-type
 
@@ -2316,113 +2337,267 @@ (define kmscon-command
    (description "Start the @command{kmscon} virtual terminal emulator for the
 Linux @dfn{kernel mode setting} (KMS).")))
 
+
+;;;
+;;; Static networking.
+;;;
+
+(define (ipv6-address? str)
+  "Return true if STR denotes an IPv6 address."
+  (false-if-exception (->bool (inet-pton AF_INET6 str))))
+
 (define-record-type* <static-networking>
   static-networking make-static-networking
   static-networking?
-  (interface static-networking-interface)
-  (ip static-networking-ip)
-  (netmask static-networking-netmask
-           (default #f))
-  (gateway static-networking-gateway              ;FIXME: doesn't belong here
-           (default #f))
+  (addresses static-networking-addresses)         ;list of <network-address>
+  (links     static-networking-links (default '())) ;list of <network-link>
+  (routes    static-networking-routes (default '())) ;list of <network-routes>
   (provision static-networking-provision
-             (default #f))
+             (default '(networking)))
   (requirement static-networking-requirement
-               (default '()))
+               (default '(udev)))
   (name-servers static-networking-name-servers    ;FIXME: doesn't belong here
                 (default '())))
 
-(define static-networking-shepherd-service
+(define-record-type* <network-address>
+  network-address make-network-address
+  network-address?
+  (device    network-address-device)              ;string--e.g., "en01"
+  (value     network-address-value)               ;string--CIDR notation
+  (ipv6?     network-address-ipv6?                ;Boolean
+             (thunked)
+             (default
+               (ipv6-address? (cidr->ip (network-address-value this-record))))))
+
+(define-record-type* <network-link>
+  network-link make-network-link
+  network-link?
+  (name      network-link-name)                   ;string--e.g, "v0p0"
+  (type      network-link-type)                   ;symbol--e.g.,'veth
+  (arguments network-link-arguments))             ;list
+
+(define-record-type* <network-route>
+  network-route make-network-route
+  network-route?
+  (destination network-route-destination)
+  (source      network-route-source (default #f))
+  (device      network-route-device (default #f))
+  (ipv6?       network-route-ipv6? (thunked)
+               (default
+                 (or (ipv6-address? (network-route-destination this-record))
+                     (and=> (network-route-gateway this-record)
+                            ipv6-address?))))
+  (gateway     network-route-gateway (default #f)))
+
+(define* (cidr->netmask str #:optional (family AF_INET))
+  "Given @var{str}, a string in CIDR notation (e.g., \"1.2.3.4/24\"), return
+the netmask as a string like \"255.255.255.0\"."
+  (match (string-split str #\/)
+    ((ip (= string->number bits))
+     (let ((mask (ash (- (expt 2 bits) 1)
+                      (- (if (= family AF_INET6) 128 32)
+                         bits))))
+       (inet-ntop family mask)))
+    (_ #f)))
+
+(define (cidr->ip str)
+  "Strip the netmask bit of @var{str}, a CIDR-notation IP/netmask address."
+  (match (string-split str #\/)
+    ((or (ip _) (ip))
+     ip)))
+
+(define* (ip+netmask->cidr ip netmask #:optional (family AF_INET))
+  "Return the CIDR notation (a string) for @var{ip} and @var{netmask}, two
+@var{family} address strings, where @var{family} is @code{AF_INET} or
+@code{AF_INET6}."
+  (let* ((netmask (inet-pton family netmask))
+         (bits    (logcount netmask)))
+    (string-append ip "/" (number->string bits))))
+
+(define (static-networking->hurd-pfinet-options config)
+  "Return command-line options for the Hurd's pfinet translator corresponding
+to CONFIG."
+  (unless (null? (static-networking-links config))
+    ;; XXX: Presumably this is not supported, or perhaps could be approximated
+    ;; by running separate pfinet instances in some cases?
+    (warning (G_ "network links are currently ignored on GNU/Hurd~%")))
+
+  (match (static-networking-addresses config)
+    ((and addresses (first _ ...))
+     `("--ipv6" "/servers/socket/26"
+       "--interface" ,(network-address-device first)
+       ,@(append-map (lambda (address)
+                       `(,(if (network-address-ipv6? address)
+                              "--address6"
+                              "--address")
+                         ,(cidr->ip (network-address-value address))
+                         ,@(match (cidr->netmask (network-address-value address)
+                                                 (if (network-address-ipv6? address)
+                                                     AF_INET6
+                                                     AF_INET))
+                             (#f '())
+                             (mask (list "--netmask" mask)))))
+                     addresses)
+       ,@(append-map (lambda (route)
+                       (match route
+                         (($ <network-route> "default" #f device _ gateway)
+                          (if (network-route-ipv6? route)
+                              `("--gateway6" ,gateway)
+                              `("--gateway" ,gateway)))
+                         (($ <network-route> destination)
+                          (warning (G_ "ignoring network route for '~a'~%")
+                                   destination)
+                          '())))
+                     (static-networking-routes config))))))
+
+(define (network-set-up/hurd config)
+  "Set up networking for the Hurd."
+  ;; The Hurd implements SIOCGIFADDR and other old-style ioctls, but the only
+  ;; way to set up IPv6 is by starting pfinet with the right options.
+  (if (equal? (static-networking-provision config) '(loopback))
+      (scheme-file "set-up-pflocal" #~(begin 'nothing-to-do! #t))
+      (scheme-file "set-up-pfinet"
+                   (with-imported-modules '((guix build utils))
+                     #~(begin
+                         (use-modules (guix build utils)
+                                      (ice-9 format))
+
+                         ;; TODO: Do that without forking.
+                         (let ((options '#$(static-networking->hurd-pfinet-options
+                                            config)))
+                           (format #t "starting '~a~{ ~s~}'~%"
+                                   #$(file-append hurd "/hurd/pfinet")
+                                   options)
+                           (apply invoke #$(file-append hurd "/bin/settrans") "-fac"
+                                  "/servers/socket/2"
+                                  #$(file-append hurd "/hurd/pfinet")
+                                  options)))))))
+
+(define (network-tear-down/hurd config)
+  (scheme-file "tear-down-pfinet"
+               (with-imported-modules '((guix build utils))
+                 #~(begin
+                     (use-modules (guix build utils))
+
+                     ;; Forcefully terminate pfinet.  XXX: In theory this
+                     ;; should just undo the addresses and routes of CONFIG;
+                     ;; this could be done using ioctls like SIOCDELRT, but
+                     ;; these are IPv4-only; another option would be to use
+                     ;; fsysopts but that seems to crash pfinet.
+                     (invoke #$(file-append hurd "/bin/settrans") "-fg"
+                             "/servers/socket/2")
+                     #f))))
+
+(define network-set-up/linux
   (match-lambda
-    (($ <static-networking> interface ip netmask gateway provision
-                            requirement name-servers)
+    (($ <static-networking> addresses links routes)
+     (scheme-file "set-up-network"
+                  (with-extensions (list guile-netlink)
+                    #~(begin
+                        (use-modules (ip addr) (ip link) (ip route))
+
+                        #$@(map (lambda (address)
+                                  #~(begin
+                                      (addr-add #$(network-address-device address)
+                                                #$(network-address-value address)
+                                                #:ipv6?
+                                                #$(network-address-ipv6? address))
+                                      ;; FIXME: loopback?
+                                      (link-set #$(network-address-device address)
+                                                #:up #t)))
+                                addresses)
+                        #$@(map (match-lambda
+                                  (($ <network-link> name type arguments)
+                                   #~(link-add #$name #$type
+                                               #:type-args '#$arguments)))
+                                links)
+                        #$@(map (lambda (route)
+                                  #~(route-add #$(network-route-destination route)
+                                               #:device
+                                               #$(network-route-device route)
+                                               #:ipv6?
+                                               #$(network-route-ipv6? route)
+                                               #:via
+                                               #$(network-route-gateway route)
+                                               #:src
+                                               #$(network-route-source route)))
+                                routes)
+                        #t))))))
+
+(define network-tear-down/linux
+  (match-lambda
+    (($ <static-networking> addresses links routes)
+     (scheme-file "tear-down-network"
+                  (with-extensions (list guile-netlink)
+                    #~(begin
+                        (use-modules (ip addr) (ip link) (ip route)
+                                     (netlink error)
+                                     (srfi srfi-34))
+
+                        (define-syntax-rule (false-if-netlink-error exp)
+                          (guard (c ((netlink-error? c) #f))
+                            exp))
+
+                        ;; Wrap calls in 'false-if-netlink-error' so this
+                        ;; script goes as far as possible undoing the effects
+                        ;; of "set-up-network".
+
+                        #$@(map (lambda (route)
+                                  #~(false-if-netlink-error
+                                     (route-del #$(network-route-destination route)
+                                                #:device
+                                                #$(network-route-device route)
+                                                #:ipv6?
+                                                #$(network-route-ipv6? route)
+                                                #:via
+                                                #$(network-route-gateway route)
+                                                #:src
+                                                #$(network-route-source route))))
+                                routes)
+                        #$@(map (match-lambda
+                                  (($ <network-link> name type arguments)
+                                   #~(false-if-netlink-error
+                                      (link-del #$name))))
+                                links)
+                        #$@(map (lambda (address)
+                                  #~(false-if-netlink-error
+                                     (addr-del #$(network-address-device
+                                                  address)
+                                               #$(network-address-value address)
+                                               #:ipv6?
+                                               #$(network-address-ipv6? address))))
+                                addresses)
+                        #f))))))
+
+(define (static-networking-shepherd-service config)
+  (match config
+    (($ <static-networking> addresses links routes
+                            provision requirement name-servers)
      (let ((loopback? (and provision (memq 'loopback provision))))
-       (define set-up-via-ioctl
-         #~(let* ((addr     (inet-pton AF_INET #$ip))
-                  (sockaddr (make-socket-address AF_INET addr 0))
-                  (mask     (and #$netmask (inet-pton AF_INET #$netmask)))
-                  (maskaddr (and mask
-                                 (make-socket-address AF_INET mask 0)))
-                  (gateway  (and #$gateway
-                                 (inet-pton AF_INET #$gateway)))
-                  (gatewayaddr (and gateway
-                                    (make-socket-address AF_INET
-                                                         gateway 0))))
-             (configure-network-interface #$interface sockaddr
-                                          (logior IFF_UP
-                                                  #$(if loopback?
-                                                        #~IFF_LOOPBACK
-                                                        0))
-                                          #:netmask maskaddr)
-             (when gateway
-               (let ((sock (socket AF_INET SOCK_DGRAM 0)))
-                 (add-network-route/gateway sock gatewayaddr)
-                 (close-port sock)))))
-
-       (define tear-down-via-ioctl
-         #~(let ((sock (socket AF_INET SOCK_STREAM 0)))
-             (when #$gateway
-               (delete-network-route sock
-                                     (make-socket-address AF_INET
-                                                          INADDR_ANY 0)))
-             (set-network-interface-flags sock #$interface 0)
-             (close-port sock)
-             #f))
-
-       (define set-up-via-netlink
-         (with-extensions (list guile-netlink)
-           #~(let ((ip #$(if netmask
-                             #~(ip+netmask->cidr #$ip #$netmask)
-                             ip)))
-               (addr-add #$interface ip)
-               (when #$gateway
-                 (route-add "default" #:device #$interface
-                            #:via #$gateway))
-               (link-set #$interface #:up #t))))
-
-       (define tear-down-via-netlink
-         (with-extensions (list guile-netlink)
-           #~(begin
-               (link-set #$interface #:down #t)
-               (when #$gateway
-                 (route-del "default" #:device #$interface))
-               (addr-del #$interface #$ip)
-               #f)))
-
-       (define helpers
-         #~(define (ip+netmask->cidr ip netmask)
-             ;; Return the CIDR notation (a string) for IP and NETMASK, two
-             ;; IPv4 address strings.
-             (let* ((netmask (inet-pton AF_INET netmask))
-                    (bits    (logcount netmask)))
-               (string-append ip "/" (number->string bits)))))
-
        (shepherd-service
 
         (documentation
          "Bring up the networking interface using a static IP address.")
         (requirement requirement)
-        (provision (or provision
-                       (list (symbol-append 'networking-
-                                            (string->symbol interface)))))
+        (provision provision)
 
         (start #~(lambda _
                    ;; Return #t if successfully started.
-                   #$helpers
-                   (if (string-contains %host-type "-linux")
-                       #$set-up-via-netlink
-                       #$set-up-via-ioctl)))
+                   (load #$(let-system (system target)
+                             (if (string-contains (or target system) "-linux")
+                                 (network-set-up/linux config)
+                                 (network-set-up/hurd config))))))
         (stop #~(lambda _
                   ;; Return #f is successfully stopped.
-                  (if (string-contains %host-type "-linux")
-                      #$tear-down-via-netlink
-                      #$tear-down-via-ioctl)))
-        (modules `((ip addr)
-                   (ip link)
-                   (ip route)
-                   ,@%default-modules))
+                  (load #$(let-system (system target)
+                            (if (string-contains (or target system) "-linux")
+                                (network-tear-down/linux config)
+                                (network-tear-down/hurd config))))))
         (respawn? #f))))))
 
+(define (static-networking-shepherd-services networks)
+  (map static-networking-shepherd-service networks))
+
 (define (static-networking-etc-files interfaces)
   "Return a /etc/resolv.conf entry for INTERFACES or the empty list."
   (match (delete-duplicates
@@ -2441,30 +2616,6 @@ (define (static-networking-etc-files interfaces)
 # Generated by 'static-networking-service'.\n"
                                       content))))))))
 
-(define (static-networking-shepherd-services interfaces)
-  "Return the list of Shepherd services to bring up INTERFACES, a list of
-<static-networking> objects."
-  (define (loopback? service)
-    (memq 'loopback (shepherd-service-provision service)))
-
-  (let ((services (map static-networking-shepherd-service interfaces)))
-    (match (remove loopback? services)
-      (()
-       ;; There's no interface other than 'loopback', so we assume that the
-       ;; 'networking' service will be provided by dhclient or similar.
-       services)
-      ((non-loopback ...)
-       ;; Assume we're providing all the interfaces, and thus, provide a
-       ;; 'networking' service.
-       (cons (shepherd-service
-              (provision '(networking))
-              (requirement (append-map shepherd-service-provision
-                                       services))
-              (start #~(const #t))
-              (stop #~(const #f))
-              (documentation "Bring up all the networking interfaces."))
-             services)))))
-
 (define static-networking-service-type
   ;; The service type for statically-defined network interfaces.
   (service-type (name 'static-networking)
@@ -2482,12 +2633,13 @@ (define static-networking-service-type
 services of this type is a list of @code{static-networking} objects, one per
 network interface.")))
 
-(define* (static-networking-service interface ip
-                                    #:key
-                                    netmask gateway provision
-                                    ;; Most interfaces require udev to be usable.
-                                    (requirement '(udev))
-                                    (name-servers '()))
+(define-deprecated (static-networking-service interface ip
+                                              #:key
+                                              netmask gateway provision
+                                              ;; Most interfaces require udev to be usable.
+                                              (requirement '(udev))
+                                              (name-servers '()))
+  static-networking-service-type
   "Return a service that starts @var{interface} with address @var{ip}.  If
 @var{netmask} is true, use it as the network mask.  If @var{gateway} is true,
 it must be a string specifying the default network gateway.
@@ -2498,11 +2650,24 @@ (define* (static-networking-service interface ip
 to handle."
   (simple-service 'static-network-interface
                   static-networking-service-type
-                  (list (static-networking (interface interface) (ip ip)
-                                           (netmask netmask) (gateway gateway)
-                                           (provision provision)
-                                           (requirement requirement)
-                                           (name-servers name-servers)))))
+                  (list (static-networking
+                         (addresses
+                          (list (network-address
+                                 (device interface)
+                                 (value (if netmask
+                                            (ip+netmask->cidr ip netmask)
+                                            ip))
+                                 (ipv6? #f))))
+                         (routes
+                          (if gateway
+                              (list (network-route
+                                     (destination "default")
+                                     (gateway gateway)
+                                     (ipv6? #f)))
+                              '()))
+                         (requirement requirement)
+                         (provision (or provision '(networking)))
+                         (name-servers name-servers)))))
 
 
 (define %base-services
@@ -2534,10 +2699,12 @@ (define %base-services
                                          (tty "tty6")))
 
         (service static-networking-service-type
-                 (list (static-networking (interface "lo")
-                                          (ip "127.0.0.1")
-                                          (requirement '())
-                                          (provision '(loopback)))))
+                 (list (static-networking
+                        (addresses (list (network-address
+                                          (device "lo")
+                                          (value "127.0.0.1"))))
+                        (requirement '())
+                        (provision '(loopback)))))
         (syslog-service)
         (service urandom-seed-service-type)
         (service guix-service-type)
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index 0794671ce4..0e73ca0d99 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -79,11 +79,28 @@ (define %base-services/hurd
         (service hurd-getty-service-type (hurd-getty-configuration
                                           (tty "tty2")))
         (service static-networking-service-type
-                 (list (static-networking (interface "lo")
-                                          (ip "127.0.0.1")
-                                          (requirement '())
-                                          (provision '(loopback networking))
-                                          (name-servers '("10.0.2.3")))))
+                 (list (static-networking
+                        (addresses
+                         (list (network-address
+                                (device "lo")
+                                (value "127.0.0.1"))))
+                        (requirement '())
+                        (provision '(loopback)))
+                       (static-networking
+                        (addresses
+                         ;; The default QEMU guest address.  To get "eth0",
+                         ;; you need QEMU to emulate a device for which Mach
+                         ;; has an in-kernel driver, for instance with:
+                         ;; --device rtl8139,netdev=net0 --netdev user,id=net0
+                         (list (network-address
+                                (device "eth0")
+                                (value "10.0.2.15/24"))))
+                        (routes
+                         (list (network-route
+                                (destination "default")
+                                (gateway "10.0.2.2"))))
+                        (provision '(networking))
+                        (name-servers '("10.0.2.3")))))
         (syslog-service)
         (service guix-service-type
                  (guix-configuration
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index 7b394184ad..bdfe580145 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -408,10 +408,13 @@ (define bare-bones-os
 
           ;; Loopback device, needed by OpenSSH notably.
           (service static-networking-service-type
-                   (list (static-networking (interface "lo")
-                                            (ip "127.0.0.1")
-                                            (requirement '())
-                                            (provision '(loopback)))))
+                   (list (static-networking
+                          (addresses
+                           (list (network-address
+                                  (device "lo")
+                                  (value "127.0.0.1"))))
+                          (requirement '())
+                          (provision '(loopback)))))
 
           (service wpa-supplicant-service-type)
           (dbus-service)
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm
index 131428c128..c66af279f2 100644
--- a/gnu/tests/networking.scm
+++ b/gnu/tests/networking.scm
@@ -337,7 +337,7 @@ (define marionette
                              (srfi srfi-1))
                 (live-service-running
                  (find (lambda (live)
-                         (memq 'networking-ovs0
+                         (memq 'networking
                                (live-service-provision live)))
                        (current-services))))
              marionette))
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 09/10] services: Define '%loopback-static-networking'.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-10-ludo@gnu.org
* gnu/services/base.scm (%loopback-static-networking): New variable.
(%base-services): Use it.
* gnu/system/hurd.scm (%base-services/hurd): Use it.
* gnu/system/install.scm (%installation-services): Use it.
* doc/guix.texi (Networking Setup): Document it.
---
doc/guix.texi | 7 +++++++
gnu/services/base.scm | 17 +++++++++++------
gnu/system/hurd.scm | 8 +-------
gnu/system/install.scm | 8 +-------
4 files changed, 20 insertions(+), 20 deletions(-)

Toggle diff (100 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 85e76991d9..2e72eb64d2 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -16940,6 +16940,13 @@ List of arguments for this type of link.
 @end table
 @end deftp
 
+@cindex loopback device
+@defvr {Scheme Variable} %loopback-static-networking
+This is the @code{static-networking} record representing the ``loopback
+device'', @code{lo}, for IP addresses 127.0.0.1 and ::1, and providing
+the @code{loopback} Shepherd service.
+@end defvr
+
 @cindex networking, with QEMU
 @cindex QEMU, networking
 @defvr {Scheme Variable} %qemu-static-networking
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index e78add4e20..d996a7b07c 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -113,6 +113,7 @@ (define-module (gnu services base)
             static-networking-service
             static-networking-service-type
 
+            %loopback-static-networking
             %qemu-static-networking
 
             udev-configuration
@@ -2671,6 +2672,15 @@ (define-deprecated (static-networking-service interface ip
                          (provision (or provision '(networking)))
                          (name-servers name-servers)))))
 
+(define %loopback-static-networking
+  ;; The loopback device.
+  (static-networking
+   (addresses (list (network-address
+                     (device "lo")
+                     (value "127.0.0.1"))))
+   (requirement '())
+   (provision '(loopback))))
+
 (define %qemu-static-networking
   ;; Networking configuration for QEMU's user-mode network stack (info "(QEMU)
   ;; Using the user mode network stack").
@@ -2715,12 +2725,7 @@ (define %base-services
                                          (tty "tty6")))
 
         (service static-networking-service-type
-                 (list (static-networking
-                        (addresses (list (network-address
-                                          (device "lo")
-                                          (value "127.0.0.1"))))
-                        (requirement '())
-                        (provision '(loopback)))))
+                 (list %loopback-static-networking))
         (syslog-service)
         (service urandom-seed-service-type)
         (service guix-service-type)
diff --git a/gnu/system/hurd.scm b/gnu/system/hurd.scm
index ec8484d746..2acc7b7e11 100644
--- a/gnu/system/hurd.scm
+++ b/gnu/system/hurd.scm
@@ -79,13 +79,7 @@ (define %base-services/hurd
         (service hurd-getty-service-type (hurd-getty-configuration
                                           (tty "tty2")))
         (service static-networking-service-type
-                 (list (static-networking
-                        (addresses
-                         (list (network-address
-                                (device "lo")
-                                (value "127.0.0.1"))))
-                        (requirement '())
-                        (provision '(loopback)))
+                 (list %loopback-static-networking
 
                        ;; QEMU user-mode networking.  To get "eth0", you need
                        ;; QEMU to emulate a device for which Mach has an
diff --git a/gnu/system/install.scm b/gnu/system/install.scm
index bdfe580145..073d7df1db 100644
--- a/gnu/system/install.scm
+++ b/gnu/system/install.scm
@@ -408,13 +408,7 @@ (define bare-bones-os
 
           ;; Loopback device, needed by OpenSSH notably.
           (service static-networking-service-type
-                   (list (static-networking
-                          (addresses
-                           (list (network-address
-                                  (device "lo")
-                                  (value "127.0.0.1"))))
-                          (requirement '())
-                          (provision '(loopback)))))
+                   (list %loopback-static-networking))
 
           (service wpa-supplicant-service-type)
           (dbus-service)
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 04/10] gnu: guile-netlink: Allow cross-compilation.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-5-ludo@gnu.org
* gnu/packages/guile-xyz.scm (guile-netlink)[arguments]: Remove,
since #:tests? #f is unnecessary.
[native-inputs]: Add GUILE-3.0.
---
gnu/packages/guile-xyz.scm | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

Toggle diff (22 lines)
diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index 628d81710a..2751abc8e8 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -4777,14 +4777,13 @@ (define-public guile-netlink
         (base32
          "1x1rx6agjdah56r50cfs41vyvycydyjdq0plq3jxgvl1q2dar1gw"))))
     (build-system gnu-build-system)
-    (arguments
-     `(#:tests? #f)); no tests
     (inputs
      `(("guile" ,guile-3.0)))
     (native-inputs
      `(("automake" ,automake)
        ("autoconf" ,autoconf)
        ("pkg-config" ,pkg-config)
+       ("guile" ,guile-3.0)                    ;for 'guild compile' + guile.m4
        ("texinfo" ,texinfo)))
     (home-page "https://git.lepiller.eu/guile-netlink")
     (synopsis "Netlink protocol implementation for Guile")
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 06/10] services: secret-service: Turn into a Shepherd service.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-7-ludo@gnu.org
* gnu/services/virtualization.scm (secret-service-activation): Remove.
(secret-service-shepherd-services): New procedure.
(secret-service-type)[extensions]: Remove ACTIVATION-SERVICE-TYPE
extension. Add SHEPHERD-ROOT-SERVICE-TYPE and
USER-PROCESSES-SERVICE-TYPE extensions.
* gnu/build/secret-service.scm (delete-file*): New procedure.
(secret-service-receive-secrets): Use it.
---
gnu/build/secret-service.scm | 17 ++++++++++++-
gnu/services/virtualization.scm | 45 ++++++++++++++++++++++++---------
2 files changed, 49 insertions(+), 13 deletions(-)

Toggle diff (103 lines)
diff --git a/gnu/build/secret-service.scm b/gnu/build/secret-service.scm
index 46dcf1b9c3..4e183e11e8 100644
--- a/gnu/build/secret-service.scm
+++ b/gnu/build/secret-service.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -111,6 +111,15 @@ (define (send-files sock)
        (close-port sock)
        #f))))
 
+(define (delete-file* file)
+  "Ensure FILE does not exist."
+  (catch 'system-error
+    (lambda ()
+      (delete-file file))
+    (lambda args
+      (unless (= ENOENT (system-error-errno args))
+        (apply throw args)))))
+
 (define (secret-service-receive-secrets port)
   "Listen to local PORT and wait for a secret service client to send secrets.
 Write them to the file system.  Return the list of files installed on success,
@@ -170,6 +179,12 @@ (define (read-secrets port)
                    (log "installing file '~a' (~a bytes)...~%"
                         file size)
                    (mkdir-p (dirname file))
+
+                   ;; It could be that FILE already exists, for instance
+                   ;; because it has been created by a service's activation
+                   ;; snippet (e.g., SSH host keys).  Delete it.
+                   (delete-file* file)
+
                    (call-with-output-file file
                      (lambda (output)
                        (dump port output size)
diff --git a/gnu/services/virtualization.scm b/gnu/services/virtualization.scm
index 1a5744ffbf..b1b10afed6 100644
--- a/gnu/services/virtualization.scm
+++ b/gnu/services/virtualization.scm
@@ -898,23 +898,44 @@ (define qemu-guest-agent-service-type
 ;;; Secrets for guest VMs.
 ;;;
 
-(define (secret-service-activation port)
-  "Return an activation snippet that fetches sensitive material at local PORT,
+(define (secret-service-shepherd-services port)
+  "Return a Shepherd service that fetches sensitive material at local PORT,
 over TCP.  Reboot upon failure."
-  (with-imported-modules '((gnu build secret-service)
-                           (guix build utils))
-    #~(begin
-        (use-modules (gnu build secret-service))
-        (let ((sent (secret-service-receive-secrets #$port)))
-          (unless sent
-            (sleep 3)
-            (reboot))))))
+  ;; This is a Shepherd service, rather than an activation snippet, to make
+  ;; sure it is started once 'networking' is up so it can accept incoming
+  ;; connections.
+  (list
+   (shepherd-service
+    (documentation "Fetch secrets from the host at startup time.")
+    (provision '(secret-service-client))
+    (requirement '(loopback networking))
+    (modules '((gnu build secret-service)
+               (guix build utils)))
+    (start (with-imported-modules '((gnu build secret-service)
+                                    (guix build utils))
+             #~(lambda ()
+                 ;; Since shepherd's output port goes to /dev/log, write this
+                 ;; message to stderr so it's visible on the Mach console.
+                 (format (current-error-port)
+                         "receiving secrets from the host...~%")
+                 (force-output (current-error-port))
+
+                 (let ((sent (secret-service-receive-secrets #$port)))
+                   (unless sent
+                     (sleep 3)
+                     (reboot))))))
+    (stop #~(const #f)))))
 
 (define secret-service-type
   (service-type
    (name 'secret-service)
-   (extensions (list (service-extension activation-service-type
-                                        secret-service-activation)))
+   (extensions (list (service-extension shepherd-root-service-type
+                                        secret-service-shepherd-services)
+
+                     ;; Make every Shepherd service depend on
+                     ;; 'secret-service-client'.
+                     (service-extension user-processes-service-type
+                                        (const '(secret-service-client)))))
    (description
     "This service fetches secret key and other sensitive material over TCP at
 boot time.  This service is meant to be used by virtual machines (VMs) that
-- 
2.33.0
L
L
Ludovic Courtès wrote on 15 Nov 2021 23:30
[PATCH v2 05/10] services: static-networking: Use Guile-Netlink on GNU/Linux.
(address . 51440@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20211115223044.10943-6-ludo@gnu.org
* gnu/services/base.scm (static-networking-shepherd-service): Define
'set-up-via-ioctl', 'tear-down-via-ioctl', 'set-up-via-netlink',
'tear-down-via-netlink', and 'helpers' and use them in 'start' and
'stop'. Add (ip *) modules to 'modules'.
---
gnu/services/base.scm | 102 +++++++++++++++++++++++++++++-------------
1 file changed, 72 insertions(+), 30 deletions(-)

Toggle diff (131 lines)
diff --git a/gnu/services/base.scm b/gnu/services/base.scm
index 50865055fe..d5ee03bbbd 100644
--- a/gnu/services/base.scm
+++ b/gnu/services/base.scm
@@ -53,6 +53,7 @@ (define-module (gnu services base)
   #:use-module (gnu packages bash)
   #:use-module ((gnu packages base)
                 #:select (coreutils glibc glibc-utf8-locales))
+  #:autoload   (gnu packages guile-xyz) (guile-netlink)
   #:use-module (gnu packages package-management)
   #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
   #:use-module (gnu packages linux)
@@ -2336,6 +2337,66 @@ (define static-networking-shepherd-service
     (($ <static-networking> interface ip netmask gateway provision
                             requirement name-servers)
      (let ((loopback? (and provision (memq 'loopback provision))))
+       (define set-up-via-ioctl
+         #~(let* ((addr     (inet-pton AF_INET #$ip))
+                  (sockaddr (make-socket-address AF_INET addr 0))
+                  (mask     (and #$netmask (inet-pton AF_INET #$netmask)))
+                  (maskaddr (and mask
+                                 (make-socket-address AF_INET mask 0)))
+                  (gateway  (and #$gateway
+                                 (inet-pton AF_INET #$gateway)))
+                  (gatewayaddr (and gateway
+                                    (make-socket-address AF_INET
+                                                         gateway 0))))
+             (configure-network-interface #$interface sockaddr
+                                          (logior IFF_UP
+                                                  #$(if loopback?
+                                                        #~IFF_LOOPBACK
+                                                        0))
+                                          #:netmask maskaddr)
+             (when gateway
+               (let ((sock (socket AF_INET SOCK_DGRAM 0)))
+                 (add-network-route/gateway sock gatewayaddr)
+                 (close-port sock)))))
+
+       (define tear-down-via-ioctl
+         #~(let ((sock (socket AF_INET SOCK_STREAM 0)))
+             (when #$gateway
+               (delete-network-route sock
+                                     (make-socket-address AF_INET
+                                                          INADDR_ANY 0)))
+             (set-network-interface-flags sock #$interface 0)
+             (close-port sock)
+             #f))
+
+       (define set-up-via-netlink
+         (with-extensions (list guile-netlink)
+           #~(let ((ip #$(if netmask
+                             #~(ip+netmask->cidr #$ip #$netmask)
+                             ip)))
+               (addr-add #$interface ip)
+               (when #$gateway
+                 (route-add "default" #:device #$interface
+                            #:via #$gateway))
+               (link-set #$interface #:up #t))))
+
+       (define tear-down-via-netlink
+         (with-extensions (list guile-netlink)
+           #~(begin
+               (link-set #$interface #:down #t)
+               (when #$gateway
+                 (route-del "default" #:device #$interface))
+               (addr-del #$interface #$ip)
+               #f)))
+
+       (define helpers
+         #~(define (ip+netmask->cidr ip netmask)
+             ;; Return the CIDR notation (a string) for IP and NETMASK, two
+             ;; IPv4 address strings.
+             (let* ((netmask (inet-pton AF_INET netmask))
+                    (bits    (logcount netmask)))
+               (string-append ip "/" (number->string bits)))))
+
        (shepherd-service
 
         (documentation
@@ -2347,38 +2408,19 @@ (define static-networking-shepherd-service
 
         (start #~(lambda _
                    ;; Return #t if successfully started.
-                   (let* ((addr     (inet-pton AF_INET #$ip))
-                          (sockaddr (make-socket-address AF_INET addr 0))
-                          (mask     (and #$netmask
-                                         (inet-pton AF_INET #$netmask)))
-                          (maskaddr (and mask
-                                         (make-socket-address AF_INET
-                                                              mask 0)))
-                          (gateway  (and #$gateway
-                                         (inet-pton AF_INET #$gateway)))
-                          (gatewayaddr (and gateway
-                                            (make-socket-address AF_INET
-                                                                 gateway 0))))
-                     (configure-network-interface #$interface sockaddr
-                                                  (logior IFF_UP
-                                                          #$(if loopback?
-                                                                #~IFF_LOOPBACK
-                                                                0))
-                                                  #:netmask maskaddr)
-                     (when gateway
-                       (let ((sock (socket AF_INET SOCK_DGRAM 0)))
-                         (add-network-route/gateway sock gatewayaddr)
-                         (close-port sock))))))
+                   #$helpers
+                   (if (string-contains %host-type "-linux")
+                       #$set-up-via-netlink
+                       #$set-up-via-ioctl)))
         (stop #~(lambda _
                   ;; Return #f is successfully stopped.
-                  (let ((sock (socket AF_INET SOCK_STREAM 0)))
-                    (when #$gateway
-                      (delete-network-route sock
-                                            (make-socket-address
-                                             AF_INET INADDR_ANY 0)))
-                    (set-network-interface-flags sock #$interface 0)
-                    (close-port sock)
-                    #f)))
+                  (if (string-contains %host-type "-linux")
+                      #$tear-down-via-netlink
+                      #$tear-down-via-ioctl)))
+        (modules `((ip addr)
+                   (ip link)
+                   (ip route)
+                   ,@%default-modules))
         (respawn? #f))))))
 
 (define (static-networking-etc-files interfaces)
-- 
2.33.0
L
L
Ludovic Courtès wrote on 17 Nov 2021 18:13
Re: bug#51440: [PATCH 00/10] Declarative static networking interface
(address . 51440@debbugs.gnu.org)
87lf1mu2ls.fsf_-_@gnu.org
Hi!

Ludovic Courtès <ludo@gnu.org> skribis:

Toggle quote (11 lines)
> tests: Add 'static-networking' test.
> tests: openvswitch: Check whether ovs0 is up.
> doc: Add new "Networking Setup" node for the main setup options.
> gnu: guile-netlink: Allow cross-compilation.
> services: static-networking: Use Guile-Netlink on GNU/Linux.
> services: secret-service: Turn into a Shepherd service.
> services: static-networking: Change interface to mimic netlink.
> services: Define '%qemu-static-networking'.
> services: Define '%loopback-static-networking'.
> tests: Replace uses of deprecated 'static-networking-service'.

I pushed this as ‘wip-networking-netlink’ to make it easier for people
to test with something like:

guix time-machine --branch=wip-networking-netlink -- \
reconfigure …

Useful test scenarios:

• You’re already using the ‘static-networking-service’ procedure; it’s
now deprecated but you can reconfigure without changing your config
file and check that networking works the same as before.

• Using the new ‘static-networking’ records to define your network,
particularly with IPv6 connectivity, crazy routes, or anything that
was not previously possible.

Thanks in advance. :-)

Ludo’.
J
J
Jonathan Brielmaier wrote on 17 Nov 2021 20:36
Re: [bug#51440] [PATCH 00/10] Declarative static networking interface
(address . guix-patches@gnu.org)
ad371789-a3ec-f679-4158-a0a706eafeb8@web.de
On 17.11.21 18:13, Ludovic Courtès wrote:> Useful test scenarios
Mine is much simpler. I use GNOME and want to end the "war" between
NetworkManager and dnsmasq. At the moment I only configured IPv4 as
Vivien said in IRC that IPv6 is a bit broken.

I stumbled across the missing `(list )` around `static-networking` in
your example. In the doc/manual commit although its correct :)

If one uses %desktop-services don't forget to remove
network-manager-service-type...
V
V
Vivien Kraus wrote on 17 Nov 2021 20:36
Static IPv6 address is reversed!
(address . 51440@debbugs.gnu.org)
a923e293b331608d69adc91b463db003d6cd8838.camel@planete-kraus.eu
Dear guix,

The static networking service looks great, but when I tried to assign
address 2a00:5881:4008:2810::309/64 to my interface, I end up (when
looking at ip -6 address) with 903::1028:840:8158:2a/64.

Since the bytes are reversed, I would look at guile-netlink and check
if all byte orders are correct when using bytevectors :)

g!inggbudey ppHa

Vivien
L
L
Ludovic Courtès wrote on 10 Dec 2021 11:51
Re: bug#51440: [PATCH 00/10] Declarative static networking interface
(name . Vivien Kraus)(address . vivien@planete-kraus.eu)(address . 51440@debbugs.gnu.org)
87y24sag1w.fsf_-_@gnu.org
⹁iH

Vivien Kraus <vivien@planete-kraus.eu> skribis:

Toggle quote (7 lines)
> The static networking service looks great, but when I tried to assign
> address 2a00:5881:4008:2810::309/64 to my interface, I end up (when
> looking at ip -6 address) with 903::1028:840:8158:2a/64.
>
> Since the bytes are reversed, I would look at guile-netlink and check
> if all byte orders are correct when using bytevectors :)

Julien fixed this interesting bug in Guile-Netlink 1.1.1, which is now
in ‘master’ (thanks!).

I rebased ‘wip-networking-netlink’ to get this fix.

Could you give it another try?

Any other issues left? If not, I think we could go ahead and merge it!

Thanks,
Ludo’.
V
V
Vivien Kraus wrote on 11 Dec 2021 13:56
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 51440@debbugs.gnu.org)
eb43650562161233e33f880043823c1e26d1c3a4.camel@planete-kraus.eu
Hi,

Le vendredi 10 décembre 2021 à 11:51 +0100, Ludovic Courtès a écrit :
Toggle quote (16 lines)
> Vivien Kraus <vivien@planete-kraus.eu> skribis:
>
> > The static networking service looks great, but when I tried to assign
> > address 2a00:5881:4008:2810::309/64 to my interface, I end up (when
> > looking at ip -6 address) with 903::1028:840:8158:2a/64.
> >
> > Since the bytes are reversed, I would look at guile-netlink and check
> > if all byte orders are correct when using bytevectors :)
>
> Julien fixed this interesting bug in Guile-Netlink 1.1.1, which is now
> in ‘master’ (thanks!).
>
> I rebased ‘wip-networking-netlink’ to get this fix.
>
> Could you give it another try?

The IP seems good.

Toggle quote (2 lines)
> Any other issues left?

I have a couple:
- I get an extra IPv6 (inet6 xxxx/64 scope global dynamic mngtmpaddr
valid_lft forever preferred_lft forever) that I did not ask for and
that takes precedence as a source for the default route, which defeats
the purpose. I’m not sure it’s guile-netlink’s fault.
- Now opensmtpd fails to start with:

Dec 11 12:01:32 localhost smtpd[5368]: info: OpenSMTPD 6.8.0p2 starting
Dec 11 12:01:32 localhost smtpd[5373]: pony express: listen: Address
already in use
Dec 11 12:01:32 localhost smtpd[5369]: smtpd: process ca socket closed

Maybe it’s unrelated, but that’s a problem for me.

Vivien
-----BEGIN PGP SIGNATURE-----

iQGzBAABCAAdFiEEq4yIHjMvkliPpwQnO7C8EjLYuCwFAmG0n+oACgkQO7C8EjLY
uCxeiwv/Trb1VGONkAe0e/njsVGzhKl1t5O8mNcAMc5YUR8p+QRZuSLiwfCYg2WV
66PW5kKVCrxVyhDqyVGarMQIRFbE9ccxFR5tiQW1n7Kp2sLOK8zwsbP5+DTsfGcq
0ydlN0YrgiQ2ukPOlZqjEctcDkk++Jl4Nnqf/ai2LLfExZ6OjuY+6/pPtsvfPQDb
3GdFRe+sPs7rYnqHPHwJfP7Q9A1PYx/V9AnizhKhhYYfWERVFX2iWhIG/KbvF2/P
QMRUwd+twlMUNjrBxESwGDyR3d6ydeqTCLhUf1gUYBoAE3fBlDzZK8Ez71oa40S/
HiyJisuR5ZYeGwNDi4Qu8oHth65DTUlBWqJG+/3+HB35DhYquX8o0lrShOwTdvx9
HwM9uDFdyvPDDDsroJ67013XSw5sNY2D9gJqvFPrMuGgfWVOdpHFim/Jan8rx7GE
/nTs2gnmS5Bix2JXAJp8Zn5H6B7BIr1Jplg9XCLLBK9ljBXOdcKUqnFrYtMZHkrs
qugpSGm0
=3sqj
-----END PGP SIGNATURE-----


L
L
Ludovic Courtès wrote on 11 Dec 2021 22:39
(name . Vivien Kraus)(address . vivien@planete-kraus.eu)
87fsqy6cu0.fsf_-_@gnu.org
Hi Vivien,

Vivien Kraus <vivien@planete-kraus.eu> skribis:

Toggle quote (3 lines)
> Le vendredi 10 décembre 2021 à 11:51 +0100, Ludovic Courtès a écrit :
>> Vivien Kraus <vivien@planete-kraus.eu> skribis:

[...]

Toggle quote (9 lines)
>> Julien fixed this interesting bug in Guile-Netlink 1.1.1, which is now
>> in ‘master’ (thanks!).
>>
>> I rebased ‘wip-networking-netlink’ to get this fix.
>>
>> Could you give it another try?
>
> The IP seems good.

\o/

Toggle quote (8 lines)
>> Any other issues left?
>
> I have a couple:
> - I get an extra IPv6 (inet6 xxxx/64 scope global dynamic mngtmpaddr
> valid_lft forever preferred_lft forever) that I did not ask for and
> that takes precedence as a source for the default route, which defeats
> the purpose. I’m not sure it’s guile-netlink’s fault.

Hmm, what’s that IPv6 address? Is it here even if you do not configure
any IPv6 address in ‘static-networking’?

Julien, could the ‘link-set’ call in ‘network-set-up/linux’ be the
culprit?

#$@(map (lambda (address)
#~(begin
(addr-add #$(network-address-device address)
#$(network-address-value address)
#:ipv6?
#$(network-address-ipv6? address))
;; FIXME: loopback?
(link-set #$(network-address-device address)
#:up #t)))
addresses)

It seems to be the only way to mark the device as “up”, but since it has
arguments that seem redundant with those of ‘addr-add’, I wonder if
something could go wrong here.

Thanks for testing, Vivien!

Ludo’.
J
J
Julien Lepiller wrote on 11 Dec 2021 23:19
(address . 51440@debbugs.gnu.org)
2E9D7B32-584F-4DDD-B040-D84888F34EF4@lepiller.eu
Le 11 décembre 2021 16:39:19 GMT-05:00, "Ludovic Courtès" <ludo@gnu.org> a écrit :
Toggle quote (53 lines)
>Hi Vivien,
>
>Vivien Kraus <vivien@planete-kraus.eu> skribis:
>
>> Le vendredi 10 décembre 2021 à 11:51 +0100, Ludovic Courtès a écrit :
>>> Vivien Kraus <vivien@planete-kraus.eu> skribis:
>
>[...]
>
>>> Julien fixed this interesting bug in Guile-Netlink 1.1.1, which is now
>>> in ‘master’ (thanks!).
>>>
>>> I rebased ‘wip-networking-netlink’ to get this fix.
>>>
>>> Could you give it another try?
>>
>> The IP seems good.
>
>\o/
>
>>> Any other issues left?
>>
>> I have a couple:
>> - I get an extra IPv6 (inet6 xxxx/64 scope global dynamic mngtmpaddr
>> valid_lft forever preferred_lft forever) that I did not ask for and
>> that takes precedence as a source for the default route, which defeats
>> the purpose. I’m not sure it’s guile-netlink’s fault.
>
>Hmm, what’s that IPv6 address? Is it here even if you do not configure
>any IPv6 address in ‘static-networking’?
>
>Julien, could the ‘link-set’ call in ‘network-set-up/linux’ be the
>culprit?
>
> #$@(map (lambda (address)
> #~(begin
> (addr-add #$(network-address-device address)
> #$(network-address-value address)
> #:ipv6?
> #$(network-address-ipv6? address))
> ;; FIXME: loopback?
> (link-set #$(network-address-device address)
> #:up #t)))
> addresses)
>
>It seems to be the only way to mark the device as “up”, but since it has
>arguments that seem redundant with those of ‘addr-add’, I wonder if
>something could go wrong here.
>
>Thanks for testing, Vivien!
>
>Ludo’.

I don't think so. Setting the interface up will always assign a link-local address (starts with fe80), and that's not under netlink control. Then, maybe once the interface is up, it may react to an RA from the router and get an additional address that way? Not sure.
V
V
Vivien Kraus wrote on 12 Dec 2021 00:32
(name . Ludovic Courtès)(address . ludo@gnu.org)
0e79f5765c75a56e88880cd12a1c0a9404d2d5bc.camel@planete-kraus.eu
Le samedi 11 décembre 2021 à 22:39 +0100, Ludovic Courtès a écrit :
Toggle quote (12 lines)
> > > Any other issues left?
> >
> > I have a couple:
> > - I get an extra IPv6 (inet6 xxxx/64 scope global dynamic
> > mngtmpaddr
> > valid_lft forever preferred_lft forever) that I did not ask for and
> > that takes precedence as a source for the default route, which
> > defeats
> > the purpose. I’m not sure it’s guile-netlink’s fault.
>
> Hmm, what’s that IPv6 address?  

So now I’m back to the DHCP setting.

I configured the DHCP server on my router to give anyone 2 IPv6
addresses: one that I configure with a static lease, and another one.
On the luci interface of my router, I see that the default mode for the
DHCP server is "stateful + stateless", which I guess translates to the
two addresses I get on the client machine. In fact, this is the
default, so I didn’t especially chose it that way.

If I keep the analogy, the "stateless" IP looks a lot like the
problematic IP I get in the static configuration.

I switch my DHCP server configuration to "stateful only", and now I
only have the static lease on the DHCP client configuration.

Let’s go back to the static networking configuration.

And now, the parasitic IP address is gone.

So, I guess there are 3 explanations:
1. That IP was committed to disk when I was running the DHCP
configuration, and got activated by default when I switched to the new
static configuration;
2. What guix considers a static client configuration talks to what
librecmc calls the DHCPv6 server and decides whether it’s OK to assign
a stateless IP depending on what the server says;
3. Some network stuff happens way above my understanding.

Anyway, I consider that problem solved for me.

Now I switch back to the DHCP configuration, otherwise the SMTP server
won’t start and I can’t send this email…

Vivien
-----BEGIN PGP SIGNATURE-----

iQGzBAABCAAdFiEEq4yIHjMvkliPpwQnO7C8EjLYuCwFAmG1NPgACgkQO7C8EjLY
uCyLQwv+MpSeNMcGlJrEktduIIM20tp8KgoFun92OWb8w/5MZ+/TVGj5UK8pKG1T
l5Dqc+aTsra+97cW2rhiohxhUjFTwvhB1FOY0K9OxJj7CkqoesXbf+3C9xCSFUUG
xUK0Z8ddjuFx5NLPSMd1RGfcJmFTn1LzpiKUd0dEZnF11MXIVe7O4K/cUBqJeV/q
D+mNSzxWXkXwBg5Jvokdp2NhDs0s2g6JDnmzW8clwJCiHe4FtzvKuPRbvsTtI9a8
wia3iE//rA2ZIH3BLFecwxLuyWcArFuUrOGLurGvz+C8p2a7xbkFwUMpOPWlWU3f
WUQgLBTCCiBFYF3VWGmitivKWNc1SiYhME7grwgmZAxmV4BBNnJqh+tdZHqGISl4
HDBaqJdxSA+k4RgIHub1si0NWLbqA/DqDgbrepykAtgf/IJCG+/yhgnos8b/zYGT
WFDt81zVndULQA1kcQasuUuTI2X9fLRzSstel7ZeY7e0Ekne2hTUGRwtZHjspMsW
cEB5tzMj
=H1iN
-----END PGP SIGNATURE-----


L
L
Ludovic Courtès wrote on 12 Dec 2021 23:00
(name . Vivien Kraus)(address . vivien@planete-kraus.eu)
875yrt4h74.fsf@gnu.org
Hi,

Vivien Kraus <vivien@planete-kraus.eu> skribis:

Toggle quote (7 lines)
> I switch my DHCP server configuration to "stateful only", and now I
> only have the static lease on the DHCP client configuration.
>
> Let’s go back to the static networking configuration.
>
> And now, the parasitic IP address is gone.

In your initial testing, you did not reboot, right?

The ‘stop’ method of the ‘networking’ Shepherd service created by
‘static-networking-service-type’ only deletes addresses and routes that
it (supposedly) created itself. Thus, if there are stale addresses
created previously, they’ll stick around. It could be what happened
here.

[...]

Toggle quote (2 lines)
> Anyway, I consider that problem solved for me.

\o/

Toggle quote (3 lines)
> Now I switch back to the DHCP configuration, otherwise the SMTP server
> won’t start and I can’t send this email…

Heh. :-)

Thanks,
Ludo’.
V
V
Vivien Kraus wrote on 12 Dec 2021 23:26
(name . Ludovic Courtès)(address . ludo@gnu.org)
b9cbffc4115fd9f52d4a8146451da3c0bdb4435a.camel@planete-kraus.eu
Hi!

Le dimanche 12 décembre 2021 à 23:00 +0100, Ludovic Courtès a écrit :
Toggle quote (2 lines)
> In your initial testing, you did not reboot, right?

I always reboot after every reconfiguration, because I can, and usually
when I wildly change the networking configuration like that the
networking service fails to upgrade, and with it everything else, so I
can’t do anything with the machine before rebooting it.

However, as I was trying a NetworkManager-based solution today, I
noticed that the configuration persists after a reboot: NetworkManager
tried to replicate what was there before. So I would not be surprised
if other pieces of networking configuration could survive a reboot.

Toggle quote (9 lines)
> > Anyway, I consider that problem solved for me.
>
> \o/
>
> > Now I switch back to the DHCP configuration, otherwise the SMTP
> server
> > won’t start and I can’t send this email…
>
> Heh. :-)
L
L
Ludovic Courtès wrote on 13 Dec 2021 00:11
(name . Vivien Kraus)(address . vivien@planete-kraus.eu)
87mtl52zbm.fsf_-_@gnu.org
I went ahead and pushed this series:

c8609493ba news: Add entry about 'static-networking-service-type'.
f73ba627ab tests: Replace uses of deprecated 'static-networking-service'.
5967aee398 services: Define '%loopback-static-networking'.
1644f4f1f8 services: Define '%qemu-static-networking'.
223f1b1eb3 services: static-networking: Change interface to mimic netlink.
39e3b4b7ce services: secret-service: Turn into a Shepherd service.
0cc742b261 services: static-networking: Use Guile-Netlink on GNU/Linux.
1759292c8b gnu: guile-netlink: Allow cross-compilation.
a4d33fef31 doc: Add new "Networking Setup" node for the main setup options.
33c498b9ee tests: openvswitch: Check whether ovs0 is up.
72f140c253 tests: Add 'static-networking' test.

Let me know if anything’s amiss!

Thanks,
Ludo’.
Closed
M
M
Mathieu Othacehe wrote on 13 Dec 2021 18:29
(address . 51440@debbugs.gnu.org)(address . ludo@gnu.org)
87k0g8fm6y.fsf@gnu.org
Hey Ludo,

Toggle quote (2 lines)
> 72f140c253 tests: Add 'static-networking' test.

Looks like there could be an issue with this test, see:

Thanks,

Mathieu
V
V
Vivien Kraus wrote on 14 Dec 2021 12:17
(name . Ludovic Courtès)(address . ludo@gnu.org)
874k7bv39r.fsf@planete-kraus.eu
Hi,

Ludovic Courtès <ludo@gnu.org> writes:
Toggle quote (6 lines)
> Vivien Kraus <vivien@planete-kraus.eu> skribis:
>> Now I switch back to the DHCP configuration, otherwise the SMTP server
>> won’t start and I can’t send this email…
>
> Heh. :-)

That problem is solved if I don’t ask for it to listen to interfaces but
rather to addresses. So now I can fully switch to the new static
networking service. I’m happy I found a solution that checks all boxes
at last :D
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCAAdFiEEq4yIHjMvkliPpwQnO7C8EjLYuCwFAmG4frAACgkQO7C8EjLY
uCwycQv+PiyVMaQdGGwbliPgl1h8tOmTA3wgtBCkEIbnaHsdtiPHLceWnd7LjQs+
Md5OSQPOF1AVhFeLLK34wHgLCnx4cdQqGfzr3x22skc++Pm8jAGBOfqz8mBdAUKA
wRH4Dr+WuwWHl1Bn5dZxx5eJYh0t/U1Wau43U9mzmqGU7pj3R1bvnliLnTsnWIto
n4RhaitDaY98Rp52NeaCPFucnxZDzZMaVO2mqHoi8+ZxSiZXAjHaDE7S25l6pBsc
8oPamhZbs1hcPTL3v2WuichPUUT65M9h+3e+yfhuN6bWiAdaAQqPkB3/ZxC3PWxc
bnR1g8edIwwIAY51nkLa+bt6t9P8Nb5HK1JtsF8mX1lp5/A824AVg3HWiJ/+TUFE
3srqGJ/OwLDXHdboMVwNFA6VSk5Ngg9jUVtrJaI7pdmC9pNep083cIqCRhHsg862
tErodR5wvfs0oA9/3ZNP35EhiYZ2TS1dj6twCqhWYwfdPmOqEnrxgxslCDdsU2ij
i79WyNvw
=zDIZ
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 14 Dec 2021 16:03
(name . Vivien Kraus)(address . vivien@planete-kraus.eu)
874k7b1b5y.fsf@gnu.org
Hi,

Vivien Kraus <vivien@planete-kraus.eu> skribis:

Toggle quote (12 lines)
> Ludovic Courtès <ludo@gnu.org> writes:
>> Vivien Kraus <vivien@planete-kraus.eu> skribis:
>>> Now I switch back to the DHCP configuration, otherwise the SMTP server
>>> won’t start and I can’t send this email…
>>
>> Heh. :-)
>
> That problem is solved if I don’t ask for it to listen to interfaces but
> rather to addresses. So now I can fully switch to the new static
> networking service. I’m happy I found a solution that checks all boxes
> at last :D

Nice, thanks again for testing and reporting!

Ludo’.
?
Your comment

This issue is archived.

To comment on this conversation send email to 51440@debbugs.gnu.org