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 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.

Note
1. kdump_setup_vlan/bond/... are no longer called in subshells in order
   to modify global variables like unique_netifs
2. The original kdump_install_net is renamed to better reflect its
   current function

Signed-off-by: Coiby Xu <coxu@redhat.com>
Reviewed-by: Thomas Haller <thaller@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
This commit is contained in:
Coiby Xu 2021-09-17 13:02:07 +08:00
parent 62355ebe5a
commit 63c3805c48

View File

@ -2,6 +2,14 @@
_DRACUT_KDUMP_NM_TMP_DIR="/tmp/$$-DRACUT_KDUMP_NM" _DRACUT_KDUMP_NM_TMP_DIR="/tmp/$$-DRACUT_KDUMP_NM"
_save_kdump_netifs() {
unique_netifs[$1]=1
}
_get_kdump_netifs() {
echo -n "${!unique_netifs[@]}"
}
cleanup() { cleanup() {
rm -rf "$_DRACUT_KDUMP_NM_TMP_DIR" rm -rf "$_DRACUT_KDUMP_NM_TMP_DIR"
} }
@ -103,39 +111,6 @@ source_ifcfg_file() {
fi 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 # $1: repeat times
# $2: string to be repeated # $2: string to be repeated
# $3: separator # $3: separator
@ -246,89 +221,6 @@ cal_netmask_by_prefix() {
fi 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() { kdump_get_mac_addr() {
cat "/sys/class/net/$1/address" cat "/sys/class/net/$1/address"
} }
@ -474,102 +366,55 @@ kdump_install_nmconnections() {
kdump_setup_bridge() { kdump_setup_bridge() {
local _netdev=$1 local _netdev=$1
local _brif _dev _mac _kdumpdev local _dev
for _dev in "/sys/class/net/$_netdev/brif/"*; do for _dev in "/sys/class/net/$_netdev/brif/"*; do
[[ -e $_dev ]] || continue [[ -e $_dev ]] || continue
_dev=${_dev##*/} _dev=${_dev##*/}
_kdumpdev=$_dev
if kdump_is_bond "$_dev"; then if kdump_is_bond "$_dev"; then
(kdump_setup_bond "$_dev" "$(get_nmcli_connection_apath_by_ifname "$_dev")") || exit 1 kdump_setup_bond "$_dev" || return 1
elif kdump_is_team "$_dev"; then elif kdump_is_team "$_dev"; then
kdump_setup_team "$_dev" kdump_setup_team "$_dev"
elif kdump_is_vlan "$_dev"; then elif kdump_is_vlan "$_dev"; then
kdump_setup_vlan "$_dev" 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 fi
_brif+="$_kdumpdev," _save_kdump_netifs "$_dev"
done 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() { kdump_setup_bond() {
local _netdev="$1" local _netdev="$1"
local _conpath="$2" local _dev
local _dev _mac _slaves _kdumpdev _bondoptions
for _dev in $(cat "/sys/class/net/$_netdev/bonding/slaves"); do for _dev in $(< "/sys/class/net/$_netdev/bonding/slaves"); do
_mac=$(kdump_get_perm_addr "$_dev") _save_kdump_netifs "$_dev"
_kdumpdev=$(kdump_setup_ifname "$_dev")
echo -n " ifname=$_kdumpdev:$_mac" >> "${initdir}/etc/cmdline.d/42bond.conf"
_slaves+="$_kdumpdev,"
done 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() { kdump_setup_team() {
local _netdev=$1 local _netdev=$1
local _dev _mac _slaves _kdumpdev local _dev
for _dev in $(teamnl "$_netdev" ports | awk -F':' '{print $2}'); do for _dev in $(teamnl "$_netdev" ports | awk -F':' '{print $2}'); do
_mac=$(kdump_get_perm_addr "$_dev") _save_kdump_netifs "$_dev"
_kdumpdev=$(kdump_setup_ifname "$_dev")
echo -n " ifname=$_kdumpdev:$_mac" >> "${initdir}/etc/cmdline.d/44team.conf"
_slaves+="$_kdumpdev,"
done 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() { kdump_setup_vlan() {
local _netdev=$1 local _netdev=$1
local _phydev local _parent_netif
local _netmac
local _kdumpdev
_phydev="$(awk '/^Device:/{print $2}' /proc/net/vlan/"$_netdev")" _parent_netif="$(awk '/^Device:/{print $2}' /proc/net/vlan/"$_netdev")"
_netmac="$(kdump_get_mac_addr "$_phydev")"
#Just support vlan over bond and team #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!" derror "Vlan over bridge is not supported!"
exit 1 exit 1
elif kdump_is_bond "$_phydev"; then elif kdump_is_bond "$_parent_netif"; then
(kdump_setup_bond "$_phydev" "$(get_nmcli_connection_apath_by_ifname "$_phydev")") || exit 1 kdump_setup_bond "$_parent_netif" || return 1
echo " vlan=$(kdump_setup_ifname "$_netdev"):$_phydev" > "${initdir}/etc/cmdline.d/43vlan.conf" elif kdump_is_team "$_parent_netif"; then
elif kdump_is_team "$_phydev"; then kdump_setup_team "$_parent_netif" || return 1
(kdump_setup_team "$_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"
fi fi
_save_kdump_netifs "$_parent_netif"
} }
# find online znet device # find online znet device
@ -656,20 +501,16 @@ kdump_get_remote_ip() {
echo "$_remote" echo "$_remote"
} }
# Setup dracut to bring up network interface that enable # Collect netifs needed by kdump
# initramfs accessing giving destination
# $1: destination host # $1: destination host
kdump_install_net() { kdump_collect_netif_usage() {
local _destaddr _srcaddr _route _netdev _conpath kdumpnic local _destaddr _srcaddr _route _netdev kdumpnic
local _static _proto _ip_conf _ip_opts _ifname_opts
local _znet_netdev _znet_conpath local _znet_netdev _znet_conpath
_destaddr=$(kdump_get_remote_ip "$1") _destaddr=$(kdump_get_remote_ip "$1")
_route=$(kdump_get_ip_route "$_destaddr") _route=$(kdump_get_ip_route "$_destaddr")
_srcaddr=$(kdump_get_ip_route_field "$_route" "src") _srcaddr=$(kdump_get_ip_route_field "$_route" "src")
_netdev=$(kdump_get_ip_route_field "$_route" "dev") _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") kdumpnic=$(kdump_setup_ifname "$_netdev")
_znet_netdev=$(find_online_znet_device) _znet_netdev=$(find_online_znet_device)
@ -681,58 +522,42 @@ kdump_install_net() {
fi fi
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 if kdump_is_bridge "$_netdev"; then
kdump_setup_bridge "$_netdev" kdump_setup_bridge "$_netdev"
elif kdump_is_bond "$_netdev"; then elif kdump_is_bond "$_netdev"; then
(kdump_setup_bond "$_netdev" "$_conpath") || exit 1 kdump_setup_bond "$_netdev" || return 1
elif kdump_is_team "$_netdev"; then elif kdump_is_team "$_netdev"; then
kdump_setup_team "$_netdev" kdump_setup_team "$_netdev"
elif kdump_is_vlan "$_netdev"; then elif kdump_is_vlan "$_netdev"; then
kdump_setup_vlan "$_netdev" kdump_setup_vlan "$_netdev"
else
_ifname_opts=" ifname=$kdumpnic:$_netmac"
echo "$_ifname_opts" >> "$_ip_conf"
fi fi
_save_kdump_netifs "$_netdev"
kdump_setup_dns "$_netdev" "$_conpath"
if [[ ! -f ${initdir}/etc/cmdline.d/50neednet.conf ]]; then if [[ ! -f ${initdir}/etc/cmdline.d/50neednet.conf ]]; then
# network-manager module needs this parameter # network-manager module needs this parameter
echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf" echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf"
fi fi
# Save netdev used for kdump as cmdline if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpnic.conf ]]; then
# 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 "kdumpnic=$kdumpnic" > "${initdir}/etc/cmdline.d/60kdumpnic.conf"
echo "bootdev=$kdumpnic" > "${initdir}/etc/cmdline.d/70bootdev.conf" fi
if is_ipv6_address "$_srcaddr"; then
ipv6_usage[$_netdev]=1
else
ipv4_usage[$_netdev]=1
fi
}
# Setup dracut to bring up network interface that enable
# initramfs accessing giving destination
kdump_install_net() {
local _netifs
_netifs=$(_get_kdump_netifs)
if [[ -n "$_netifs" ]]; then
kdump_install_nmconnections
apply_nm_initrd_generator_timeouts
fi fi
} }
@ -771,7 +596,7 @@ default_dump_target_install_conf() {
_fstype=$(get_fs_type_from_target "$_target") _fstype=$(get_fs_type_from_target "$_target")
if is_fs_type_nfs "$_fstype"; then if is_fs_type_nfs "$_fstype"; then
kdump_install_net "$_target" kdump_collect_netif_usage "$_target"
_fstype="nfs" _fstype="nfs"
else else
_target=$(kdump_get_persistent_dev "$_target") _target=$(kdump_get_persistent_dev "$_target")
@ -807,11 +632,11 @@ kdump_install_conf() {
sed -i -e "s#^${_opt}[[:space:]]\+$_val#$_opt $_pdev#" "${initdir}/tmp/$$-kdump.conf" sed -i -e "s#^${_opt}[[:space:]]\+$_val#$_opt $_pdev#" "${initdir}/tmp/$$-kdump.conf"
;; ;;
ssh | nfs) ssh | nfs)
kdump_install_net "$_val" kdump_collect_netif_usage "$_val"
;; ;;
dracut_args) dracut_args)
if [[ $(get_dracut_args_fstype "$_val") == nfs* ]]; then if [[ $(get_dracut_args_fstype "$_val") == nfs* ]]; then
kdump_install_net "$(get_dracut_args_target "$_val")" kdump_collect_netif_usage "$(get_dracut_args_target "$_val")"
fi fi
;; ;;
kdump_pre | kdump_post | extra_bins) kdump_pre | kdump_post | extra_bins)
@ -933,7 +758,7 @@ kdump_setup_iscsi_device() {
[[ -n $username_in ]] && userpwd_in_str=":$username_in:$password_in" [[ -n $username_in ]] && userpwd_in_str=":$username_in:$password_in"
kdump_install_net "$tgt_ipaddr" kdump_collect_netif_usage "$tgt_ipaddr"
# prepare netroot= command line # prepare netroot= command line
# FIXME: Do we need to parse and set other parameters like protocol, port # FIXME: Do we need to parse and set other parameters like protocol, port
@ -1097,7 +922,7 @@ kdump_configure_fence_kdump() {
# setup network for each node # setup network for each node
for node in ${nodes}; do for node in ${nodes}; do
kdump_install_net "$node" kdump_collect_netif_usage "$node"
done done
dracut_install /etc/hosts dracut_install /etc/hosts
@ -1208,6 +1033,8 @@ install() {
inst "ip" inst "ip"
fi fi
kdump_install_net
# For the lvm type target under kdump, in /etc/lvm/lvm.conf we can # For the lvm type target under kdump, in /etc/lvm/lvm.conf we can
# safely replace "reserved_memory=XXXX"(default value is 8192) with # safely replace "reserved_memory=XXXX"(default value is 8192) with
# "reserved_memory=1024" to lower memory pressure under kdump. We do # "reserved_memory=1024" to lower memory pressure under kdump. We do