From 63c3805c486adf700bafb5ad78cc9b0f55fcb345 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Fri, 17 Sep 2021 13:02:07 +0800 Subject: [PATCH] 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 Reviewed-by: Thomas Haller Reviewed-by: Philipp Rudo --- dracut-module-setup.sh | 287 ++++++++--------------------------------- 1 file changed, 57 insertions(+), 230 deletions(-) diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index ecfabc7..67468cd 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -2,6 +2,14 @@ _DRACUT_KDUMP_NM_TMP_DIR="/tmp/$$-DRACUT_KDUMP_NM" +_save_kdump_netifs() { + unique_netifs[$1]=1 +} + +_get_kdump_netifs() { + echo -n "${!unique_netifs[@]}" +} + cleanup() { rm -rf "$_DRACUT_KDUMP_NM_TMP_DIR" } @@ -103,39 +111,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 @@ -246,89 +221,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" } @@ -474,102 +366,55 @@ kdump_install_nmconnections() { 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" || return 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=[::[:]] 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" - elif kdump_is_team "$_phydev"; then - (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" + elif kdump_is_bond "$_parent_netif"; then + kdump_setup_bond "$_parent_netif" || return 1 + elif kdump_is_team "$_parent_netif"; then + kdump_setup_team "$_parent_netif" || return 1 fi + + _save_kdump_netifs "$_parent_netif" } # find online znet device @@ -656,20 +501,16 @@ kdump_get_remote_ip() { echo "$_remote" } -# Setup dracut to bring up network interface that enable -# initramfs accessing giving destination +# Collect netifs needed by kdump # $1: destination host -kdump_install_net() { - local _destaddr _srcaddr _route _netdev _conpath kdumpnic - local _static _proto _ip_conf _ip_opts _ifname_opts +kdump_collect_netif_usage() { + local _destaddr _srcaddr _route _netdev kdumpnic local _znet_netdev _znet_conpath _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) @@ -681,58 +522,42 @@ kdump_install_net() { 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" || return 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 + if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpnic.conf ]]; then 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 } @@ -771,7 +596,7 @@ default_dump_target_install_conf() { _fstype=$(get_fs_type_from_target "$_target") if is_fs_type_nfs "$_fstype"; then - kdump_install_net "$_target" + kdump_collect_netif_usage "$_target" _fstype="nfs" else _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" ;; ssh | nfs) - kdump_install_net "$_val" + kdump_collect_netif_usage "$_val" ;; dracut_args) 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 ;; kdump_pre | kdump_post | extra_bins) @@ -933,7 +758,7 @@ kdump_setup_iscsi_device() { [[ -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 # 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 for node in ${nodes}; do - kdump_install_net "$node" + kdump_collect_netif_usage "$node" done dracut_install /etc/hosts @@ -1208,6 +1033,8 @@ install() { inst "ip" fi + kdump_install_net + # 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