Compare commits

...

11 Commits

Author SHA1 Message Date
Coiby Xu 2c098ae1e4 Simplify setup_znet by copying connection profile to initrd
/usr/lib/udev/ccw_init [1] shipped by s390utils extracts the values of
SUBCHANNELS, NETTYPE and LAYER2 from /etc/sysconfig/network-scripts/ifcfg-*
or /etc/NetworkManager/system-connections/*.nmconnection to activate znet
network device. If the connection profile is copied to initrd,
there is no need to set up the "rd.znet" dracut cmdline parameter.

There are two cases addressed by this commit,
 1. znet network interface is a slave of bonding/teaming/vlan/bridging
    network. The connection profile has been copied to initrd by
    kdump_copy_nmconnection_file and it contains the info needed by
    ccw_init.
 2. znet network interface is a slave of bonding/teaming/vlan/bridging
    network. The corresponding ifcfg-*/*.nmconnection file may not contain
    info like SUBCHANNELS [2]. In this case, copy the ifcfg-*/*.nmconnection
    file that has this info to the kdump initrd. Also to prevent the copied
    connection profile from being chosen by NM, set
    connection.autoconnect=false for this connection profile.

Note
1. ccw_init doesn't care if SUBCHANNELS, NETTYPE and LAYER2 comes from
   an active NM profile or not. If an inactive NM profile contains this
   info, it needs to be copied to the kdump initrd as well.
2. "rd.znet_ifname=$_netdev:${SUBCHANNELS}" is no needed because now
   there is no renaming of s390x network interfaces when reusing
   NetworkManager profiles. rd.znet_ifname was introduced in commit
   ce0305d ("Add a new option 'rd.znet_ifname' in order to use it in udev
   rules") to address the special case of non-persistent MAC address by
   renaming a network interface by SUBCHANNELS.

[1] https://src.fedoraproject.org/rpms/s390utils/blob/rawhide/f/ccw_init
[2] https://bugzilla.redhat.com/show_bug.cgi?id=2064708

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:52:35 +08:00
Coiby Xu 8ac940570d Address the cases where a NIC has a different name in kdump kernel
A NIC may get a different name in the kdump kernel from 1st kernel
in cases like,
 - kernel assigned network interface names are not persistent e.g. [1]
 - there is an udev rule to rename the NIC in the 1st kernel but the
   kdump initrd may not have that rule e.g. [2]

If NM tries to match a NIC with a connection profile based on NIC name
i.e. connection.interface-name, it will fail the above bases. A simple
solution is to ask NM to match a connection profile by MAC address.
Note we don't need to do this for user-created NICs like vlan, bridge and
bond.

An remaining issue is passing the name of a NIC via the kdumpnic dracut
command line parameter which requires passing ifname=<interface>:<MAC> to
have fixed NIC name. But we can simply drop this requirement. kdumpnic
is needed because kdump needs to get the IP by NIC name and use the IP
to created a dumping folder named "{IP}-{DATE}". We can simply pass the
IP to the kdump kernel directly via a new dracut command line parameter
kdumpip instead. In addition to the benefit of simplifying the code,
there are other three benefits brought by this approach,
  - make use of whatever network to transfer the vmcore. Because  as long
    as we have the network to we don't care which NIC is active.
  - if obtained IP in the kdump kernel is different from the one in the
    1st kernel. "{IP}-{DATE}" would better tell where the dumped vmcore
    comes from.
  - without passing ifname=<interface>:<MAC> to kdump initrd, the
    issue of there are two interfaces with the same MAC address for
    Azure Hyper-V NIC SR-IOV [3] is resolved automatically.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1121778
[2] https://bugzilla.redhat.com/show_bug.cgi?id=810107
[3] https://bugzilla.redhat.com/show_bug.cgi?id=1962421

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:52:35 +08:00
Coiby Xu 92184499df Reduce kdump memory consumption by only installing needed NIC drivers
Even after having asked NM to stop managing a unneeded NIC, a NIC driver
may still waste memory. For example, mlx5_core uses a substantial amount
of memory during driver initialization,

======== Report format module_summary: ========
Module mlx5_core using 350.2MB (89650 pages), peak allocation 367.4MB (94056 pages)
Module squashfs using 13.1MB (3360 pages), peak allocation 13.1MB (3360 pages)
Module overlay using 2.1MB (550 pages), peak allocation 2.2MB (555 pages)
Module dns_resolver using 0.9MB (219 pages), peak allocation 5.2MB (1338 pages)
Module mlxfw using 0.7MB (172 pages), peak allocation 5.3MB (1349 pages)
======== Report format module_summary END ========

======== Report format module_top: ========
Top stack usage of module mlx5_core:
  (null) Pages: 89650 (peak: 94056)
    ret_from_fork (0xffffda088b4165f8) Pages: 60007 (peak: 60007)
      kthread (0xffffda088b4bd7e4) Pages: 60007 (peak: 60007)
        worker_thread (0xffffda088b4b48d0) Pages: 60007 (peak: 60007)
          process_one_work (0xffffda088b4b3f40) Pages: 60007 (peak: 60007)
            work_for_cpu_fn (0xffffda088b4aef00) Pages: 53906 (peak: 53906)
              local_pci_probe (0xffffda088b9e1e44) Pages: 53906 (peak: 53906)
                probe_one mlx5_core (0xffffda084f899cc8) Pages: 53518 (peak: 53518)
                  mlx5_init_one mlx5_core (0xffffda084f8994ac) Pages: 49756 (peak: 49756)
                    mlx5_function_setup.constprop.0 mlx5_core (0xffffda084f899100) Pages: 44434 (eak: 44434)
                      mlx5_satisfy_startup_pages mlx5_core (0xffffda084f8a4f24) Pages: 44434 (peak: 44434)
                    mlx5_function_setup.constprop.0 mlx5_core (0xffffda084f899078) Pages: 5285 (peak: 5285)
                      mlx5_cmd_init mlx5_core (0xffffda084f89e414) Pages: 4818 (peak: 4818)
                        mlx5_alloc_cmd_msg mlx5_core (0xffffda084f89aaa0) Pages: 4403 (peak: 4403)

This memory consumption is completely unnecessary when kdump doesn't need
this NIC. Only install needed NIC drivers to prevent this kind of waste.

Note
1. this patch depends on [1] to ask dracut to not install NIC drivers.
2. "ethtool -i" somehow fails to get the vlan driver
3. team.ko doesn't depend on the team mode drivers so we need to install
   the team mode drivers manually.

[1] https://github.com/dracutdevs/dracut/pull/1789

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:52:32 +08:00
Coiby Xu 38108118fd Reduce kdump memory consumption by not letting NetworkManager manage unneeded network interfaces
By default, NetworkManger will manage all the network interfaces and
try to set interface IFF_UP to get carrier state. Regardless of whether
the network interface is connected to a cable or not, the NIC driver
will allocate memory resources for e.g. ring buffers when setting IFF_UP.
This could be a waste of memory. For example it's found i40e consumes ~15GB
on a power machine. On this machine, i40e manages four interfaces but only
one interface is valid. This patch use "managed=false" to tell
NetworkManager to not manage network interfaces that are not needed by
kdump by putting /etc/NetworkManager/conf.d/10-kdump-netif.conf in the
initramfs.

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:51:05 +08:00
Coiby Xu 197babd57a Set up kdump network by directly copying NM connection profile to initrd
This patch setup kdump network by directly copying NM connection profile(s)
for different network setup including bond, bridge, vlan, and team. For
vlan network, rename phydev to parent_netif to improve code readability.

With the new approach, the related code to build up dracut cmdline
parameter such rd.route, ip and etc can be cleaned up. And there is no
need to to setup dns when copying .nmconnection directly to initrd
either. Note the bootdev dracut command line parameter is only used by
dracut's 35network-legacy and network-manager doesn't use it, remove
related code as well.

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:51:05 +08:00
Coiby Xu f9c5e17eb7 Stop dracut 35network-manager from running nm-initrd-generator
kexec-tools depends on dracut's 35network-manager module which will
call nm-initrd-generator. We don't want nm-initrd-generator to generate
connection profiles since we  will copy them from 1st kernel to
kdump kernel initramfs. NetworkManager >= 1.35.2 won't generate connection
profiles if there's a connection dir with rd.neednet. For Fedora/RHEL,
this connection dir is /etc/NetworkManager/system-connections. For the
details, please refer to the NetworkManager commit 79885656d3
("initrd: don't add a connection if there's a connection dir with
rd.neednet") [1]. Before the release of NetworkManager >= 1.35.2, we
need to mask /usr/libexec/nm-initrd-generator.

[1] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1010

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:51:05 +08:00
Coiby Xu 05f4ad14bb Truly wait for network connectivity to be established
nm-wait-online-initrd.service installed by dracut's 35-networkmanager
module calls nm-online with "-s" which means it returns immediately when
NetworkManager logs "startup complete". Thus it doesn't truly wait for
network connectivity to be established [1]. Remove "-s" to avoid this
undesirable effect. There are two benefits brought by this approach,
 - ssh/nfs dumping won't fail because of that the network is not ready [2]
 - users don't need to use workarounds like rd.net.carrier.timeout to
   make sure network is ready

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1485712
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1909014

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:51:05 +08:00
Coiby Xu 31daf710af Determine whether IPv4 or IPv6 is needed
According to `man nm-online`,
  "By default, connections have the ipv4.may-fail and
  ipv6.may-fail properties set to yes; this means that
  NetworkManager waits for one of the two address families to
  complete configuration before considering the connection
  activated. If you need a specific address family configured
  before network-online.target is reached, set the corresponding
  may-fail property to no."

If a NIC has an IPv4 or IPv6 address, set the corresponding may-fail
property to no. Otherwise, dumping vmcore over IPv6 could fail because
only IPv4 network is ready or vice versa.

If only IPv4 is used, disable IPv6 otherwise and vice versa.

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:51:01 +08:00
Coiby Xu 520a862c74 Clone NM connection profiles to support legacy ifcfg automatically
NetworkManager defaults to use keyfile i.e. .nmconnnection file but
still supports reading ifcfg-* file [1]. Make use of
"nmcli connection clone --temporary" to automatically convert a ifcfg-*
file to a .nmconnection file. And it's also better to modify the cloned
.nmconnection.

[1] https://fedoraproject.org/wiki/Changes/NetworkManager_keyfile_instead_of_ifcfg_rh

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:50:17 +08:00
Coiby Xu 6039ac2dda Add functions to copy NetworkManage connection profiles to the initramfs
Each network interface is manged by a NM connection. Given a list of
network interface names,  copy the NetworkManager (NM) connection
profiles i.e.  .nmconnection files to the kdump initramfs.

Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 10:48:28 +08:00
Coiby Xu 442e3f9b52 Fix error for vlan over team network interface
6f9235887f ("module-setup.sh: enable
vlan on team interface") skips establishing teaming network by mistake.
Although it could use one of slave netifs to establish connection
to transfer vmcore to remote fs, it breaks the implicit assumption of
creating an identical network topology to the 1st kernel.

Fixes: 6f92358 ("module-setup.sh: enable vlan on team interface")
Signed-off-by: Coiby Xu <coxu@redhat.com>
2022-09-20 07:04:31 +08:00
4 changed files with 313 additions and 298 deletions

View File

@ -478,25 +478,28 @@ save_vmcore_dmesg_ssh()
get_host_ip()
{
if is_nfs_dump_target || is_ssh_dump_target; then
kdumpnic=$(getarg kdumpnic=)
if [ -z "$kdumpnic" ]; then
derror "failed to get kdumpnic!"
return 1
fi
if ! kdumphost=$(ip addr show dev "$kdumpnic" | grep '[ ]*inet'); then
derror "wrong kdumpnic: $kdumpnic"
return 1
fi
kdumphost=$(echo "$kdumphost" | head -n 1 | awk '{print $2}')
kdumphost="${kdumphost%%/*}"
if [ -z "$kdumphost" ]; then
derror "wrong kdumpnic: $kdumpnic"
return 1
fi
HOST_IP=$kdumphost
if ! is_nfs_dump_target && ! is_ssh_dump_target; then
return 0
fi
return 0
_kdump_remote_ip=$(getarg kdump_remote_ip=)
if [ -z "$_kdump_remote_ip" ]; then
derror "failed to get remote IP address!"
return 1
fi
_route=$(kdump_get_ip_route "$_kdump_remote_ip")
_netdev=$(kdump_get_ip_route_field "$_route" "dev")
if ! _kdumpip=$(ip addr show dev "$_netdev" | grep '[ ]*inet'); then
derror "Failed to get IP of $_netdev"
return 1
fi
_kdumpip=$(echo "$_kdumpip" | head -n 1 | awk '{print $2}')
_kdumpip="${_kdumpip%%/*}"
HOST_IP=$_kdumpip
}
read_kdump_confs()

View File

@ -1,10 +1,29 @@
#!/bin/bash
_DRACUT_KDUMP_NM_TMP_DIR="/tmp/$$-DRACUT_KDUMP_NM"
_TMP_KDUMP_NETIFS="$_DRACUT_KDUMP_NM_TMP_DIR/kdump_netifs"
_TMP_KDUMP_NETIFS_IPv46="$_DRACUT_KDUMP_NM_TMP_DIR/kdump_netifs_ipv46"
_save_kdump_netifs() {
echo -n " $1" >> "$_TMP_KDUMP_NETIFS"
}
cleanup() {
rm -rf "$_DRACUT_KDUMP_NM_TMP_DIR"
}
# shellcheck disable=SC2154 # known issue of shellcheck https://github.com/koalaman/shellcheck/issues/1299
trap 'ret=$?; cleanup; exit $ret;' EXIT
kdump_module_init() {
if ! [[ -d "${initdir}/tmp" ]]; then
mkdir -p "${initdir}/tmp"
fi
mkdir -p "$_DRACUT_KDUMP_NM_TMP_DIR"
echo -n > "$_TMP_KDUMP_NETIFS"
echo -n > "$_TMP_KDUMP_NETIFS_IPv46"
. /lib/kdump/kdump-lib.sh
}
@ -84,39 +103,6 @@ source_ifcfg_file() {
fi
}
kdump_setup_dns() {
local _netdev="$1"
local _conpath="$2"
local _nameserver _dns _tmp array
local _dnsfile=${initdir}/etc/cmdline.d/42dns.conf
_tmp=$(get_nmcli_field_by_conpath "IP4.DNS" "$_conpath")
# shellcheck disable=SC2206
array=(${_tmp//|/ })
if [[ ${array[*]} ]]; then
for _dns in "${array[@]}"; do
echo "nameserver=$_dns" >> "$_dnsfile"
done
else
dwarning "Failed to get DNS info via nmcli output. Now try sourcing ifcfg script"
source_ifcfg_file "$_netdev"
[[ -n $DNS1 ]] && echo "nameserver=$DNS1" > "$_dnsfile"
[[ -n $DNS2 ]] && echo "nameserver=$DNS2" >> "$_dnsfile"
fi
while read -r content; do
_nameserver=$(echo "$content" | grep ^nameserver)
[[ -z $_nameserver ]] && continue
_dns=$(echo "$_nameserver" | awk '{print $2}')
[[ -z $_dns ]] && continue
if [[ ! -f $_dnsfile ]] || ! grep -q "$_dns" "$_dnsfile"; then
echo "nameserver=$_dns" >> "$_dnsfile"
fi
done < "/etc/resolv.conf"
}
# $1: repeat times
# $2: string to be repeated
# $3: separator
@ -227,89 +213,6 @@ cal_netmask_by_prefix() {
fi
}
#$1: netdev name
#$2: srcaddr
#if it use static ip echo it, or echo null
kdump_static_ip() {
local _netdev="$1" _srcaddr="$2" kdumpnic="$3" _ipv6_flag
local _netmask _gateway _ipaddr _target _nexthop _prefix
_ipaddr=$(ip addr show dev "$_netdev" permanent | awk "/ $_srcaddr\/.* /{print \$2}")
if is_ipv6_address "$_srcaddr"; then
_ipv6_flag="-6"
fi
if [[ -n $_ipaddr ]]; then
_gateway=$(ip $_ipv6_flag route list dev "$_netdev" \
| awk '/^default /{print $3}' | head -n 1)
if [[ "x" != "x"$_ipv6_flag ]]; then
# _ipaddr="2002::56ff:feb6:56d5/64", _netmask is the number after "/"
_netmask=${_ipaddr#*\/}
_srcaddr="[$_srcaddr]"
_gateway="[$_gateway]"
else
_prefix=$(cut -d'/' -f2 <<< "$_ipaddr")
if ! _netmask=$(cal_netmask_by_prefix "$_prefix" "$_ipv6_flag"); then
derror "Failed to calculate netmask for $_ipaddr"
exit 1
fi
fi
echo -n "${_srcaddr}::${_gateway}:${_netmask}::"
fi
/sbin/ip $_ipv6_flag route show | grep -v default \
| grep ".*via.* $_netdev " | grep -v "^[[:space:]]*nexthop" \
| while read -r _route; do
_target=$(echo "$_route" | awk '{print $1}')
_nexthop=$(echo "$_route" | awk '{print $3}')
if [[ "x" != "x"$_ipv6_flag ]]; then
_target="[$_target]"
_nexthop="[$_nexthop]"
fi
echo "rd.route=$_target:$_nexthop:$kdumpnic"
done >> "${initdir}/etc/cmdline.d/45route-static.conf"
kdump_handle_mulitpath_route "$_netdev" "$_srcaddr" "$kdumpnic"
}
kdump_handle_mulitpath_route() {
local _netdev="$1" _srcaddr="$2" kdumpnic="$3" _ipv6_flag
local _target _nexthop _route _weight _max_weight _rule
if is_ipv6_address "$_srcaddr"; then
_ipv6_flag="-6"
fi
while IFS="" read -r _route; do
if [[ $_route =~ [[:space:]]+nexthop ]]; then
_route=${_route##[[:space:]]}
# Parse multipath route, using previous _target
[[ $_target == 'default' ]] && continue
[[ $_route =~ .*via.*\ $_netdev ]] || continue
_weight=$(echo "$_route" | cut -d ' ' -f7)
if [[ $_weight -gt $_max_weight ]]; then
_nexthop=$(echo "$_route" | cut -d ' ' -f3)
_max_weight=$_weight
if [[ "x" != "x"$_ipv6_flag ]]; then
_rule="rd.route=[$_target]:[$_nexthop]:$kdumpnic"
else
_rule="rd.route=$_target:$_nexthop:$kdumpnic"
fi
fi
else
[[ -n $_rule ]] && echo "$_rule"
_target=$(echo "$_route" | cut -d ' ' -f1)
_rule="" _max_weight=0 _weight=0
fi
done >> "${initdir}/etc/cmdline.d/45route-static.conf" \
<<< "$(/sbin/ip $_ipv6_flag route show)"
[[ -n $_rule ]] && echo "$_rule" >> "${initdir}/etc/cmdline.d/45route-static.conf"
}
kdump_get_mac_addr() {
cat "/sys/class/net/$1/address"
}
@ -326,121 +229,242 @@ kdump_get_perm_addr() {
fi
}
# Prefix kernel assigned names with "kdump-". EX: eth0 -> kdump-eth0
# Because kernel assigned names are not persistent between 1st and 2nd
# kernel. We could probably end up with eth0 being eth1, eth0 being
# eth1, and naming conflict happens.
kdump_setup_ifname() {
local _ifname
use_ipv4_or_ipv6() {
local _netif=$1 _uuid=$2
# If ifname already has 'kdump-' prefix, we must be switching from
# fadump to kdump. Skip prefixing 'kdump-' in this case as adding
# another prefix may truncate the ifname. Since an ifname with
# 'kdump-' is already persistent, this should be fine.
if [[ $1 =~ eth* ]] && [[ ! $1 =~ ^kdump-* ]]; then
_ifname="kdump-$1"
else
_ifname="$1"
if [[ -v "ipv4_usage[$_netif]" ]]; then
nmcli connection modify --temporary "$_uuid" ipv4.may-fail no &> >(ddebug)
fi
echo "$_ifname"
if [[ -v "ipv6_usage[$_netif]" ]]; then
nmcli connection modify --temporary "$_uuid" ipv6.may-fail no &> >(ddebug)
fi
if [[ -v "ipv4_usage[$_netif]" ]] && [[ ! -v "ipv6_usage[$_netif]" ]]; then
nmcli connection modify --temporary "$_uuid" ipv4.method disabled &> >(ddebug)
elif [[ ! -v "ipv4_usage[$_netif]" ]] && [[ -v "ipv6_usage[$_netif]" ]]; then
nmcli connection modify --temporary "$_uuid" ipv6.method disabled &> >(ddebug)
fi
}
# nm-wait-online-initrd.service installed by dracut's 35-networkmanager
# module call nm-online with "-s" thus it doesn't wait for network connectivity
# to be established. Remove "-s" to avoid this undesirable effect.
wait_for_network_connectivity() {
local _nm_wait_online_service_file
_nm_wait_online_service_file="$initdir/usr/lib/systemd/system/nm-wait-online-initrd.service"
[[ ! -f $_nm_wait_online_service_file ]] && return
sed -i -E "/^ExecStart=\/usr\/bin\/nm-online/ {
s/ -s / /;}" "$_nm_wait_online_service_file"
}
_clone_nmconnection() {
local _clone_output _name _unique_id
_unique_id=$1
_name=$(nmcli --get-values connection.id connection show "$_unique_id")
if _clone_output=$(nmcli connection clone --temporary "$_unique_id" "$_name"); then
sed -E -n "s/.* \(.*\) cloned as.*\((.*)\)\.$/\1/p" <<< "$_clone_output"
return 0
fi
return 1
}
_match_nmconnection_by_mac() {
local _unique_id _dev _mac _mac_field
_unique_id=$1
_dev=$2
_mac=$(kdump_get_perm_addr "$_dev")
if [[ $_mac != 'not set' ]]; then
_mac_field=$(nmcli --get-values connection.type connection show "$_unique_id").mac-address
nmcli connection modify --temporary "$_unique_id" "$_mac_field" "$_mac" &> >(ddebug)
nmcli connection modify --temporary "$_unique_id" "connection.interface-name" "" &> >(ddebug)
fi
}
# Clone NM connection profiles
#
# This function makes use of "nmcli clone" to automatically convert ifcfg-*
# files to Networkmanager .nmconnection connection profiles and also modify the
# properties of .nmconnection if necessary.
clone_nmconnections() {
local _dev _cloned_nmconnection_file_path _tmp_nmconnection_file_path _old_uuid _uuid
for _dev in "${!nmconnection_map[@]}"; do
_nmconnection_file_path=${nmconnection_map[$_dev]}
_old_uuid=$(nmcli --get-values connection.uuid connection show "$_nmconnection_file_path")
if ! _uuid=$(_clone_nmconnection "$_old_uuid"); then
derror "Failed to clone $_old_uuid"
exit 1
fi
use_ipv4_or_ipv6 "$_uuid" "$_dev"
# For physical NIC i.e. non-user created NIC, ask NM to match a
# connection profile based on MAC address
_match_nmconnection_by_mac "$_uuid" "$_dev"
_cloned_nmconnection_file_path=$(nmcli --get-values UUID,FILENAME connection show | sed -n "s/^${_uuid}://p")
_tmp_nmconnection_file_path=$_DRACUT_KDUMP_NM_TMP_DIR/$(basename "$_nmconnection_file_path")
cp "$_cloned_nmconnection_file_path" "$_tmp_nmconnection_file_path"
# change uuid back to old value in case it's refered by other connection
# profile e.g. connection.master could be interface name of the master
# device or UUID of the master connection.
sed -i -E "s/(^uuid=).*$/\1${_old_uuid}/g" "$_tmp_nmconnection_file_path"
nmconnection_map[$_dev]=$_tmp_nmconnection_file_path
nmcli connection del "$_uuid" &> >(ddebug)
done
}
_install_nmconnections() {
local _dev _nmconnection_file_path _nmconnection_name _initrd_nmconnection_file_path
for _dev in "${!nmconnection_map[@]}"; do
_nmconnection_file_path=${nmconnection_map[$_dev]}
_nmconnection_name=$(basename "$_nmconnection_file_path")
_initrd_nmconnection_file_path="/etc/NetworkManager/system-connections/$_nmconnection_name"
inst "$_nmconnection_file_path" "$_initrd_nmconnection_file_path"
done
}
kdump_install_nmconnections() {
declare -A nmconnection_map ipv4_usage ipv6_usage
local _netifs _netif
_netifs=$1
for _netif in $_netifs; do
nmconnection_map[$_netif]=$_netif
done
while IFS=: read -r _netif _nmconn; do
if [[ -v "nmconnection_map[$_netif]" ]] ; then
nmconnection_map[$_netif]="$_nmconn"
fi
done <<< "$(nmcli -t -f device,filename connection show --active)"
while IFS=: read -r _ifname _ip_proc; do
if [[ $_ip_proc == 6 ]]; then
ipv6_usage[$_ifname]=1
elif [[ $_ip_proc == 4 ]]; then
ipv4_usage[$_ifname]=1
fi
done < $_TMP_KDUMP_NETIFS_IPv46
clone_nmconnections
_install_nmconnections
}
kdump_install_nm_netif_allowlist() {
local _netif _except_netif _netif_allowlist _netif_allowlist_nm_conf
for _netif in $1; do
_per_mac=$(kdump_get_perm_addr "$_netif")
if [[ "$_per_mac" != 'not set' ]]; then
_except_netif="mac:$_per_mac"
else
_except_netif="interface-name:$_netif"
fi
_netif_allowlist="${_netif_allowlist}except:${_except_netif};"
done
_netif_allowlist_nm_conf=$_DRACUT_KDUMP_NM_TMP_DIR/netif_allowlist_nm_conf
cat <<- EOF > "$_netif_allowlist_nm_conf"
[device-others]
match-device=${_netif_allowlist}
managed=false
EOF
inst "$_netif_allowlist_nm_conf" "/etc/NetworkManager/conf.d/10-kdump-netif.conf"
}
_get_nic_driver() {
ethtool -i "$1" | sed -n -E "s/driver: (.*)/\1/p"
}
kdump_install_nic_driver() {
local _netif _driver _drivers
_drivers=()
for _netif in $1; do
_driver=$(_get_nic_driver "$_netif")
if [[ -z $_driver ]]; then
derror "Failed to get the driver of $_netif"
exit 1
fi
if [[ $_driver == "802.1Q VLAN Support" ]]; then
# ethtool somehow doesn't return the driver name for a VLAN NIC
_driver=8021q
elif [[ $_driver == "team" ]]; then
# install the team mode drivers like team_mode_roundrobin.ko as well
_driver='=drivers/net/team'
fi
_drivers+=("$_driver")
done
instmods "${_drivers[@]}"
}
kdump_setup_bridge() {
local _netdev=$1
local _brif _dev _mac _kdumpdev
local _dev
for _dev in "/sys/class/net/$_netdev/brif/"*; do
[[ -e $_dev ]] || continue
_dev=${_dev##*/}
_kdumpdev=$_dev
if kdump_is_bond "$_dev"; then
(kdump_setup_bond "$_dev" "$(get_nmcli_connection_apath_by_ifname "$_dev")") || exit 1
(kdump_setup_bond "$_dev") || exit 1
elif kdump_is_team "$_dev"; then
kdump_setup_team "$_dev"
elif kdump_is_vlan "$_dev"; then
kdump_setup_vlan "$_dev"
else
_mac=$(kdump_get_mac_addr "$_dev")
_kdumpdev=$(kdump_setup_ifname "$_dev")
echo -n " ifname=$_kdumpdev:$_mac" >> "${initdir}/etc/cmdline.d/41bridge.conf"
fi
_brif+="$_kdumpdev,"
_save_kdump_netifs "$_dev"
done
echo " bridge=$_netdev:${_brif%,}" >> "${initdir}/etc/cmdline.d/41bridge.conf"
}
# drauct takes bond=<bondname>[:<bondslaves>:[:<options>]] syntax to parse
# bond. For example:
# bond=bond0:eth0,eth1:mode=balance-rr
kdump_setup_bond() {
local _netdev="$1"
local _conpath="$2"
local _dev _mac _slaves _kdumpdev _bondoptions
for _dev in $(cat "/sys/class/net/$_netdev/bonding/slaves"); do
_mac=$(kdump_get_perm_addr "$_dev")
_kdumpdev=$(kdump_setup_ifname "$_dev")
echo -n " ifname=$_kdumpdev:$_mac" >> "${initdir}/etc/cmdline.d/42bond.conf"
_slaves+="$_kdumpdev,"
local _dev
for _dev in $(< "/sys/class/net/$_netdev/bonding/slaves"); do
_save_kdump_netifs "$_dev"
done
echo -n " bond=$_netdev:${_slaves%,}" >> "${initdir}/etc/cmdline.d/42bond.conf"
_bondoptions=$(get_nmcli_field_by_conpath "bond.options" "$_conpath")
if [[ -z $_bondoptions ]]; then
dwarning "Failed to get bond configuration via nmlci output. Now try sourcing ifcfg script."
source_ifcfg_file "$_netdev"
_bondoptions="$(echo "$BONDING_OPTS" | xargs echo | tr " " ",")"
fi
if [[ -z $_bondoptions ]]; then
derror "Get empty bond options"
exit 1
fi
echo ":$_bondoptions" >> "${initdir}/etc/cmdline.d/42bond.conf"
}
kdump_setup_team() {
local _netdev=$1
local _dev _mac _slaves _kdumpdev
local _dev
for _dev in $(teamnl "$_netdev" ports | awk -F':' '{print $2}'); do
_mac=$(kdump_get_perm_addr "$_dev")
_kdumpdev=$(kdump_setup_ifname "$_dev")
echo -n " ifname=$_kdumpdev:$_mac" >> "${initdir}/etc/cmdline.d/44team.conf"
_slaves+="$_kdumpdev,"
_save_kdump_netifs "$_dev"
done
echo " team=$_netdev:${_slaves%,}" >> "${initdir}/etc/cmdline.d/44team.conf"
#Buggy version teamdctl outputs to stderr!
#Try to use the latest version of teamd.
if ! teamdctl "$_netdev" config dump > "${initdir}/tmp/$$-$_netdev.conf"; then
derror "teamdctl failed."
exit 1
fi
inst_dir /etc/teamd
inst_simple "${initdir}/tmp/$$-$_netdev.conf" "/etc/teamd/$_netdev.conf"
rm -f "${initdir}/tmp/$$-$_netdev.conf"
}
kdump_setup_vlan() {
local _netdev=$1
local _phydev
local _netmac
local _kdumpdev
local _parent_netif
_phydev="$(awk '/^Device:/{print $2}' /proc/net/vlan/"$_netdev")"
_netmac="$(kdump_get_mac_addr "$_phydev")"
_parent_netif="$(awk '/^Device:/{print $2}' /proc/net/vlan/"$_netdev")"
#Just support vlan over bond and team
if kdump_is_bridge "$_phydev"; then
if kdump_is_bridge "$_parent_netif"; then
derror "Vlan over bridge is not supported!"
exit 1
elif kdump_is_bond "$_phydev"; then
(kdump_setup_bond "$_phydev" "$(get_nmcli_connection_apath_by_ifname "$_phydev")") || exit 1
echo " vlan=$(kdump_setup_ifname "$_netdev"):$_phydev" > "${initdir}/etc/cmdline.d/43vlan.conf"
else
_kdumpdev="$(kdump_setup_ifname "$_phydev")"
echo " vlan=$(kdump_setup_ifname "$_netdev"):$_kdumpdev ifname=$_kdumpdev:$_netmac" > "${initdir}/etc/cmdline.d/43vlan.conf"
elif kdump_is_bond "$_parent_netif"; then
(kdump_setup_bond "$_parent_netif") || exit 1
elif kdump_is_team "$_parent_netif"; then
(kdump_setup_team "$_parent_netif") || exit 1
fi
_save_kdump_netifs "$_parent_netif"
}
# find online znet device
@ -471,47 +495,46 @@ find_online_znet_device() {
echo -n "$ifname"
}
# setup s390 znet cmdline
# $1: netdev (ifname)
# $2: nmcli connection path
_find_znet_nmconnection() {
LANG=C grep -s -E -i -l \
"^s390-subchannels=([0-9]\.[0-9]\.[a-f0-9]+;){0,2}" \
"$1"/*.nmconnection | LC_ALL=C sed -e "$2"
}
# setup s390 znet
#
# Note part of code is extracted from ccw_init provided by s390utils
kdump_setup_znet() {
local _netdev="$1"
local _conpath="$2"
local s390_prefix="802-3-ethernet.s390-"
local _options=""
local NETTYPE
local SUBCHANNELS
local _config_file _unique_name _NM_conf_dir
local __sed_discard_ignored_files='/\(~\|\.bak\|\.old\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'
NETTYPE=$(get_nmcli_field_by_conpath "${s390_prefix}nettype" "$_conpath")
SUBCHANNELS=$(get_nmcli_field_by_conpath "${s390_prefix}subchannels" "$_conpath")
_options=$(get_nmcli_field_by_conpath "${s390_prefix}options" "$_conpath")
_NM_conf_dir="/etc/NetworkManager/system-connections"
if [[ -z $NETTYPE || -z $SUBCHANNELS || -z $_options ]]; then
dwarning "Failed to get znet configuration via nmlci output. Now try sourcing ifcfg script."
source_ifcfg_file "$_netdev"
for i in $OPTIONS; do
_options=${_options},$i
done
_config_file=$(_find_znet_nmconnection "$initdir/$_NM_conf_dir" "$__sed_discard_ignored_files")
if [[ -n "$_config_file" ]]; then
ddebug "$_config_file has already contained the znet config"
return
fi
if [[ -z $NETTYPE || -z $SUBCHANNELS || -z $_options ]]; then
exit 1
_config_file=$(LANG=C grep -s -E -i -l \
"^[[:space:]]*SUBCHANNELS=['\"]?([0-9]\.[0-9]\.[a-f0-9]+,){0,2}" \
/etc/sysconfig/network-scripts/ifcfg-* \
| LC_ALL=C sed -e "$__sed_discard_ignored_files")
if [[ -n "$_config_file" ]]; then
LANG=c grep 'SUBCHANNELS\|NETTYPE\|OPTIONS' "$_config_file" > "$initdir/$_config_file"
else
_config_file=$(_find_znet_nmconnection "$_NM_conf_dir" "$__sed_discard_ignored_files")
fi
echo "rd.znet=${NETTYPE},${SUBCHANNELS},${_options} rd.znet_ifname=$_netdev:${SUBCHANNELS}" > "${initdir}/etc/cmdline.d/30znet.conf"
}
kdump_get_ip_route() {
local _route
if ! _route=$(/sbin/ip -o route get to "$1" 2>&1); then
derror "Bad kdump network destination: $1"
exit 1
if [[ -n "$_config_file" ]]; then
_unique_name=$(cat /proc/sys/kernel/random/uuid)
nmcli connection clone --temporary "$_config_file" "$_unique_name" &> >(ddebug)
nmcli connection modify --temporary "$_unique_name" connection.autoconnect false
inst "/run/NetworkManager/system-connections/${_unique_name}.nmconnection" "${_NM_conf_dir}/${_unique_name}.nmconnection"
nmcli connection del "$_unique_name" &> >(ddebug)
fi
echo "$_route"
}
kdump_get_ip_route_field() {
echo "$1" | sed -n -e "s/^.*\<$2\>\s\+\(\S\+\).*$/\1/p"
}
kdump_get_remote_ip() {
@ -531,80 +554,45 @@ kdump_get_remote_ip() {
# initramfs accessing giving destination
# $1: destination host
kdump_install_net() {
local _destaddr _srcaddr _route _netdev _conpath kdumpnic
local _static _proto _ip_conf _ip_opts _ifname_opts
local _znet_netdev _znet_conpath
local _destaddr _srcaddr _route _netdev _ip_proc
_destaddr=$(kdump_get_remote_ip "$1")
_route=$(kdump_get_ip_route "$_destaddr")
_srcaddr=$(kdump_get_ip_route_field "$_route" "src")
_netdev=$(kdump_get_ip_route_field "$_route" "dev")
_conpath=$(get_nmcli_connection_apath_by_ifname "$_netdev")
_netmac=$(kdump_get_mac_addr "$_netdev")
kdumpnic=$(kdump_setup_ifname "$_netdev")
_znet_netdev=$(find_online_znet_device)
if [[ -n $_znet_netdev ]]; then
_znet_conpath=$(get_nmcli_connection_apath_by_ifname "$_znet_netdev")
if ! (kdump_setup_znet "$_znet_netdev" "$_znet_conpath"); then
derror "Failed to set up znet"
exit 1
fi
fi
_static=$(kdump_static_ip "$_netdev" "$_srcaddr" "$kdumpnic")
if [[ -n $_static ]]; then
_proto=none
elif is_ipv6_address "$_srcaddr"; then
_proto=auto6
else
_proto=dhcp
fi
_ip_conf="${initdir}/etc/cmdline.d/40ip.conf"
_ip_opts=" ip=${_static}$kdumpnic:${_proto}"
# dracut doesn't allow duplicated configuration for same NIC, even they're exactly the same.
# so we have to avoid adding duplicates
# We should also check /proc/cmdline for existing ip=xx arg.
# For example, iscsi boot will specify ip=xxx arg in cmdline.
if [[ ! -f $_ip_conf ]] || ! grep -q "$_ip_opts" "$_ip_conf" \
&& ! grep -q "ip=[^[:space:]]*$_netdev" /proc/cmdline; then
echo "$_ip_opts" >> "$_ip_conf"
fi
if kdump_is_bridge "$_netdev"; then
kdump_setup_bridge "$_netdev"
elif kdump_is_bond "$_netdev"; then
(kdump_setup_bond "$_netdev" "$_conpath") || exit 1
(kdump_setup_bond "$_netdev") || exit 1
elif kdump_is_team "$_netdev"; then
kdump_setup_team "$_netdev"
elif kdump_is_vlan "$_netdev"; then
kdump_setup_vlan "$_netdev"
else
_ifname_opts=" ifname=$kdumpnic:$_netmac"
echo "$_ifname_opts" >> "$_ip_conf"
fi
kdump_setup_dns "$_netdev" "$_conpath"
_save_kdump_netifs "$_netdev"
if [[ ! -f ${initdir}/etc/cmdline.d/50neednet.conf ]]; then
# network-manager module needs this parameter
echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf"
fi
# Save netdev used for kdump as cmdline
# Whoever calling kdump_install_net() is setting up the default gateway,
# ie. bootdev/kdumpnic. So don't override the setting if calling
# kdump_install_net() for another time. For example, after setting eth0 as
# the default gate way for network dump, eth1 in the fence kdump path will
# call kdump_install_net again and we don't want eth1 to be the default
# gateway.
if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpnic.conf ]] \
&& [[ ! -f ${initdir}/etc/cmdline.d/70bootdev.conf ]]; then
echo "kdumpnic=$kdumpnic" > "${initdir}/etc/cmdline.d/60kdumpnic.conf"
echo "bootdev=$kdumpnic" > "${initdir}/etc/cmdline.d/70bootdev.conf"
# Stop dracut 35network-manger to calling nm-initrd-generator.
# Note this line of code can be removed after NetworkManager >= 1.35.2
# gets released.
echo > "${initdir}/usr/libexec/nm-initrd-generator"
if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpip.conf ]]; then
echo "kdump_remote_ip=$_destaddr" > "${initdir}/etc/cmdline.d/60kdumpip.conf"
fi
if is_ipv6_address "$_srcaddr"; then
_ip_proc=6
else
_ip_proc=4
fi
echo "$_netdev" "$_ip_proc" >> "$_TMP_KDUMP_NETIFS_IPv46"
}
# install etc/kdump/pre.d and /etc/kdump/post.d
@ -1019,7 +1007,7 @@ remove_cpu_online_rule() {
}
install() {
local arch
local arch _netifs
kdump_module_init
kdump_install_conf
@ -1078,6 +1066,16 @@ install() {
inst "ip"
fi
wait_for_network_connectivity
_netifs=$(cat "$_TMP_KDUMP_NETIFS")
if [[ -n "$_netifs" ]]; then
kdump_install_nmconnections "$_netifs"
[[ -n "$(find_online_znet_device)" ]] && kdump_setup_znet
kdump_install_nm_netif_allowlist "$_netifs"
kdump_install_nic_driver "$_netifs"
fi
# For the lvm type target under kdump, in /etc/lvm/lvm.conf we can
# safely replace "reserved_memory=XXXX"(default value is 8192) with
# "reserved_memory=1024" to lower memory pressure under kdump. We do

View File

@ -131,3 +131,17 @@ is_fs_dump_target()
{
[ -n "$(kdump_get_conf_val "ext[234]\|xfs\|btrfs\|minix")" ]
}
kdump_get_ip_route()
{
if ! _route=$(/sbin/ip -o route get to "$1" 2>&1); then
derror "Bad kdump network destination: $1"
exit 1
fi
echo "$_route"
}
kdump_get_ip_route_field()
{
echo "$1" | sed -n -e "s/^.*\<$2\>\s\+\(\S\+\).*$/\1/p"
}

View File

@ -27,7 +27,7 @@ SAVE_PATH=$(get_save_path)
OVERRIDE_RESETTABLE=0
extra_modules=""
dracut_args=(--add kdumpbase --quiet --hostonly --hostonly-cmdline --hostonly-i18n --hostonly-mode strict -o "plymouth resume ifcfg earlykdump")
dracut_args=(--add kdumpbase --quiet --hostonly --hostonly-cmdline --hostonly-i18n --hostonly-mode strict --hostonly-nics '' -o "plymouth resume ifcfg earlykdump")
MKDUMPRD_TMPDIR="$(mktemp -d -t mkdumprd.XXXXXX)"
[ -d "$MKDUMPRD_TMPDIR" ] || perror_exit "dracut: mktemp -p -d -t dracut.XXXXXX failed."