agama/live/live-root/usr/lib/dracut/modules.d/99hcn/README.md
Knut Anderssen 8a4169fe50 Fix the generator config clobbering and the multi-bond lookup
Two independent problems in parse-hcn, both pre-existing.

nm-initrd-generator unconditionally writes 15-carrier-timeout.conf to
its --run-config-dir. parse-hcn left that at the default
/run/NetworkManager/conf.d, so the HCN run overwrote the file
NetworkManager had generated from the real command line and reset a
user supplied rd.net.timeout.carrier back to the 10 s default. Point
--run-config-dir at /run/hcn/conf.d, next to the connections directory
that is already isolated the same way.

fixup_nm_connections() checked bond membership with
strstr " $BOND_NAMES " " $bond ", but BOND_NAMES is newline separated,
so the space delimited needle could only ever match when there was a
single bond. With two or more bonds the fallback branch never matched
at all. Add a flat BOND_LIST next to BOND_NAMES and use it for the
substring check. FIRST_BOND can then drop its echo | awk as well.

Related to bsc#1272445.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 09:59:59 +01:00

15 KiB

99hcn - Hybrid Cloud Network Dracut Module

Automatically configures bonded network interfaces for IBM PowerVM Hybrid Cloud Network (HCN) during initramfs boot.

Quick Start

Add to kernel command line:

rd.hcn.ip=10.2.2.69::10.2.0.1:255.255.255.0

This automatically discovers HCN devices via /proc/device-tree, creates an active-backup bond with the SR-IOV primary and vNIC backup adapters, and configures the specified IP address.

What is HCN?

Hybrid Cloud Network (HCN) on IBM PowerVM provides high-availability networking by bonding two types of network adapters:

  • Primary adapter: PCI SR-IOV Ethernet (high performance, direct hardware access)
  • Backup adapter: Virtual NIC (vNIC) through hypervisor (reliability fallback during Live Partition Migration)

The bond operates in active-backup mode with fail_over_mac=2, allowing seamless failover during hardware events or Live Partition Migration (LPM).

Kernel Parameters

rd.hcn.ip=<config>

Configures IP addressing on HCN bond interfaces. The module transforms these parameters into standard ip= parameters, automatically replacing port interface names or MAC addresses with the corresponding bond controller names.

How Interface Selection Works:

  • Single HCN bond: When no interface name or MAC address is specified, the configuration applies to the first (only) bond discovered
  • Multiple HCN bonds: Use the port interface name or port MAC address to target a specific bond. The module automatically transforms the port reference to the bond controller name (e.g., bond333e80f5)

Format Options:

# Simple method (applies to first bond)
rd.hcn.ip={dhcp|auto6|dhcp6}

# Static IP (applies to first bond)
rd.hcn.ip=<client-IP>::<gateway>:<netmask>:::<method>

# Target specific bond by port interface name
rd.hcn.ip=<port-iface>:{dhcp|auto6}
rd.hcn.ip=<client-IP>::<gateway>:<netmask>::<port-iface>:<method>

# Target specific bond by port MAC address
rd.hcn.ip=<client-IP>::<gateway>:<netmask>::<port-MAC>:<method>

Examples:

# DHCP on first bond
rd.hcn.ip=dhcp

# IPv6 autoconfiguration on first bond
rd.hcn.ip=auto6

# Static IP on first bond
rd.hcn.ip=192.168.1.10::192.168.1.1:255.255.255.0:::none

# DHCP on bond containing enP32775p1s0 (port is transformed to bond controller)
rd.hcn.ip=enP32775p1s0:dhcp

# Static IP on bond containing env6 (port is transformed to bond controller)
rd.hcn.ip=192.168.1.10::192.168.1.1:255.255.255.0::env6:none

How the transformation works: The module discovers HCN devices and their bond mappings (port → bond controller), then rewrites rd.hcn.ip parameters by replacing port references with bond names before passing them to NetworkManager's initrd generator.

rd.hcn.route=<config>

Adds static routes for HCN bond interfaces. Like rd.hcn.ip, this parameter supports port interface names or MAC addresses for targeting specific bonds in multi-bond configurations.

Format Options:

# Route on first bond (no interface specified)
rd.hcn.route=<network>/<prefix>:<gateway>

# Route on specific bond by port interface name
rd.hcn.route=<network>/<prefix>:<gateway>:<port-iface>

# Route on specific bond by port MAC address
rd.hcn.route=<network>/<prefix>:<gateway>:<port-MAC>

Examples:

# Single static route on first bond
rd.hcn.ip=192.168.1.10::192.168.1.1:255.255.255.0 \
  rd.hcn.route=10.0.0.0/8:192.168.1.1

# Multiple static routes on first bond
rd.hcn.ip=192.168.1.10::192.168.1.1:255.255.255.0 \
  rd.hcn.route=10.0.0.0/8:192.168.1.1 \
  rd.hcn.route=172.16.0.0/12:192.168.1.254

# Routes on specific bonds (multi-bond setup)
rd.hcn.ip=enP32775p1s0:dhcp \
  rd.hcn.ip=192.168.1.10::192.168.1.1:255.255.255.0::env6:none \
  rd.hcn.route=10.0.0.0/8:192.168.1.1:env6 \
  rd.hcn.route=172.16.0.0/12:192.168.1.254:env6

rd.hcn=1|0

Explicitly enables or disables HCN configuration.

Note: This parameter is optional and redundant when rd.hcn.ip or rd.hcn.route is present, as these parameters automatically trigger HCN activation. Use rd.hcn=0 to explicitly disable HCN even when other HCN parameters are present.

Standard network parameters

parse-hcn builds a command line of its own and hands it to nm-initrd-generator, so the network options you really passed are invisible to the generator unless the module copies them over. The run NetworkManager does on its own is no substitute: the ip=hcn marker keeps that run from producing any connection, so everything it would have parsed into one is thrown away.

These are carried over as they are. They name no device, so they end up in whichever connection carries the addresses:

Parameter Effect on the bond connection
nameserver=<ip> (repeatable) ipv4.dns / ipv6.dns
rd.peerdns=0 ignore-auto-dns=true
rd.net.timeout.dhcp=<seconds> dhcp-timeout
rd.net.dhcp.retry=<count> multiplies dhcp-timeout
rd.net.dhcp.vendor-class=<id> dhcp-vendor-class-identifier
rd.net.dhcp.dscp={CS0|CS4|CS6} dhcp-dscp
# DHCP on the bond, with a fixed resolver and a longer DHCP timeout
rd.hcn.ip=enP32775p1s0:dhcp \
  nameserver=192.168.1.1 rd.peerdns=0 rd.net.timeout.dhcp=60

Not carried over

  • rd.net.dhcp.client-id=, bootdev=, rd.ethtool= — each names a device. You would name a bond port, so the reference would have to be rewritten to its bond, and nm-initrd-generator creates a full connection for any device named in these, which the module would then persist to /etc/NetworkManager/system-connections.
  • vlan=, bridge=, team= — same rewriting problem, and a device stacked on top of an HCN bond also needs a way to be addressed from rd.hcn.ip, which the current syntax does not provide.
  • rd.net.dns, rd.net.dns-backend, rd.net.dns-resolve-mode, rd.net.timeout.carrier — these produce a global configuration file instead of a connection. They do not depend on HCN having resolved the bonds and NetworkManager's own generator run already wrote them to /run/NetworkManager/conf.d. For the same reason the HCN run writes its own configuration files to /run/hcn/conf.d: the generator always emits 15-carrier-timeout.conf, and with the default directory it would reset a rd.net.timeout.carrier given by the user.

Host name

The host name field of rd.hcn.ip (5th field) reaches /proc/sys/kernel/hostname, the same as on a normal ip= boot. The generator writes it to /run/NetworkManager/initrd and nm-run.sh, the initqueue/settled hook of the 35network-manager module, applies it from there. hcn-init-initrd.service is ordered Before=dracut-initqueue.service, so the file is always in place by the time the hook runs.

It does not reach /etc/hostname. That is the separate, standalone hostname= parameter, which Agama handles in the 99agama-cmdline module and persists to the installed system.

ip=hcn (internal, do not use)

This is not a user-facing parameter. The module writes it itself to /etc/cmdline.d/20-hcn.conf to announce that HCN takes care of the network, see Interaction with other modules. Use rd.hcn.ip / rd.hcn.route to configure HCN.

Passing ip=hcn on the kernel command line does not enable HCN, it only stops everybody else from configuring the network, so the system likely ends up with no network at all. Making it a proper user-facing option is part of the long-term transparent ip= work, where the port name or MAC would be given as usual (ip=<port>:hcn) and rd.hcn.* would be deprecated.

Multiple HCN Bonds

When your system has multiple HCN bonds (multiple pairs of devices with different ibm,hcn-id values), you must target specific bonds using either:

  1. Port interface name (e.g., enP32775p1s0, env6) - predictable network names known in advance from firmware/hypervisor configuration
  2. Port MAC address (e.g., 2e:7a:3c:6a:1c:00) - the logical port MAC address assigned to the port device

The module transforms these port identifiers to the actual bond controller names (e.g., bond333e80f5) before generating NetworkManager connections.

Why port identifiers? The bond controller name itself is derived from the HCN ID discovered at boot time from /proc/device-tree, which is not known in advance. However, the port interface names and MAC addresses are assigned by the hypervisor and are stable across reboots.

Examples:

# Two bonds targeted by port interface names
rd.hcn.ip=enP32775p1s0:dhcp \
  rd.hcn.ip=10.2.2.100::10.2.0.1:255.255.255.0::env6:none

# Two bonds targeted by port MAC addresses
rd.hcn.ip=10.2.2.69::10.2.0.1:255.255.255.0::2e:7a:3c:6a:1c:00:none \
  rd.hcn.ip=10.2.2.100::10.2.0.1:255.255.255.0::2e:7a:3c:6a:1c:01:none

# With dashes in MAC address (also supported)
rd.hcn.ip=10.2.2.69::10.2.0.1:255.255.255.0::2e-7a-3c-6a-1c-00:none \
  rd.hcn.ip=10.2.2.100::10.2.0.1:255.255.255.0::2e-7a-3c-6a-1c-01:none

How it works:

  1. Module discovers that enP32775p1s0 (SR-IOV) belongs to bond bond333e80f5
  2. Module discovers that env6 (vNIC) belongs to bond bond444f91a6
  3. rd.hcn.ip=enP32775p1s0:dhcp is transformed to ip=bond333e80f5:dhcp
  4. rd.hcn.ip=10.2.2.100::10.2.0.1:255.255.255.0::env6:none is transformed to ip=10.2.2.100::10.2.0.1:255.255.255.0::bond444f91a6:none
  5. NetworkManager creates connections using the bond controller names

How It Works

The HCN dracut module integrates with systemd and NetworkManager during the initramfs boot phase:

  1. Claiming the network: A cmdline hook (hcn-cmdline.sh) writes ip=hcn to /etc/cmdline.d/20-hcn.conf when HCN is requested and HCN devices are present. This marker tells NetworkManager and the other Agama dracut modules that HCN configures the network, so nobody else touches the bond ports (see Interaction with other modules)
  2. Device Discovery: Scans /proc/device-tree for devices with matching ibm,hcn-id properties, building a mapping of port devices to bond controllers
  3. Parameter Transformation: Replaces port interface names or MAC addresses in rd.hcn.* parameters with discovered bond controller names
  4. Bond Configuration: Generates bond= parameters for active-backup bonds with the discovered primary (SR-IOV) and backup (vNIC) adapters
  5. Command Line Carry-Over: Copies the remaining device independent network parameters of the real kernel command line (nameserver=, rd.peerdns=, rd.net.dhcp.*), which the generator would otherwise never see (see Standard network parameters)
  6. Profile Generation: Calls nm-initrd-generator with the transformed ip=, rd.route=, bond= and carried-over parameters to create NetworkManager connection profiles
  7. Profile Adaptation: Fixes up generated profiles for compatibility with the hcnmgr daemon (bond naming, controller references, UUIDs)
  8. Persistence: Copies adapted profiles to /etc/NetworkManager/system-connections/ for initramfs persistence
  9. System Persistence: The Agama installer copies profiles to the installed system where hcnmgr manages them at runtime

Key Design Points:

  • Two-stage persistence: Profiles are stored in /etc/NetworkManager/system-connections/ during initramfs, then copied to the installed system by Agama's save-agama-conf.sh
  • Isolated generation: Uses a custom output directory (/run/hcn/system-connections/) to prevent conflicts with standard NetworkManager profiles
  • No cmdline pollution: The transformed parameters are passed directly to nm-initrd-generator as arguments and are never written to /etc/cmdline.d/. The only thing written there is the ip=hcn marker, which nothing but HCN acts upon

Interaction with other modules

HCN cannot be configured from a cmdline hook: the bond ports only show up once udev has discovered the devices, which happens long after the command line is parsed. Everything else, though, is decided at that point, so the module reserves the network for itself as early as possible by writing ip=hcn to /etc/cmdline.d/20-hcn.conf:

  • NetworkManager skips the argument and, more importantly, does not fabricate its default DHCP connection when rd.neednet=1 was requested but the command line produced no connection. That default would bring the bond ports up on their own, breaking the bond.
  • The other Agama modules (99agama-dud, 99live-self-update, 99initrd-nmtui) only add ip=dhcp when the user did not configure the network. An ip= of any kind is enough for them to keep their hands off, hence the hook runs at priority 20, before their priority 99 hooks.

When HCN is requested but the device tree contains no HCN device, the marker is not written: parse-hcn would not configure anything either, so the other modules should keep providing their usual DHCP fallback.

The marker is an implementation detail between the module and NetworkManager. It is not meant to be typed by users: hcn-init-initrd.service does not react to it, so an ip=hcn given on the kernel command line configures nothing while still keeping the other modules away from the network.

Requirements

  • IBM PowerVM system with HCN-capable adapters (devices with ibm,hcn-id properties in /proc/device-tree)
  • NetworkManager with nm-initrd-generator support, including ip=hcn (jsc#PED-14534). Older versions treat hcn as an unknown method and generate their own wired DHCP connection, which breaks the bond
  • Agama installer (for profile persistence to installed system)
  • Supported platforms: SLES 16.1+ (NetworkManager < 1.54), Tumbleweed (NetworkManager >= 1.54)

Files

  • module-setup.sh - Dracut module installation and dependency declarations
  • hcn-cmdline.sh - Dracut cmdline hook writing the ip=hcn marker
  • parse-hcn.sh - Device discovery, bond configuration, and profile generation logic (despite the name, not a cmdline hook: it runs from the service below)
  • hcn-init-initrd.service - Systemd service orchestrating boot-time HCN setup

Documentation

See ARCHITECTURE.md for detailed design documentation, including:

  • Boot-time integration and component diagram
  • Sequential boot process flow
  • HCN-specific parameter design rationale
  • Two-stage persistence architecture
  • Profile fixup and compatibility details
  • hcnmgr daemon: Runtime management of HCN bonds in the installed system
  • Agama installer: Copies initramfs network profiles to installed system via save-agama-conf.sh
  • dracut nm-initrd-generator: Generates NetworkManager connection profiles from kernel parameters
  • NetworkManager: Activates network connections during initramfs and runtime

References