From d22786bb5af48ef665b0ceca2acaf4260633f003 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Wed, 23 Nov 2022 09:42:18 +0800 Subject: [PATCH] Address the cases where a NIC has a different name in kdump kernel Resolves: bz2076416 Upstream: Fedora Conflict: None commit 568623e69a32266a3b00225b9de6a93435c44474 Author: Coiby Xu Date: Thu Sep 23 14:25:01 2021 +0800 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=: 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=: 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 Reviewed-by: Thomas Haller Reviewed-by: Philipp Rudo Signed-off-by: Coiby Xu --- dracut-kdump.sh | 39 ++++++++++++++++------------- dracut-module-setup.sh | 57 +++++++++++++++--------------------------- kdump-lib-initramfs.sh | 14 +++++++++++ 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/dracut-kdump.sh b/dracut-kdump.sh index e38a4a3..3613cfb 100755 --- a/dracut-kdump.sh +++ b/dracut-kdump.sh @@ -480,25 +480,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() diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh index 478a0c2..2fe9e5f 100755 --- a/dracut-module-setup.sh +++ b/dracut-module-setup.sh @@ -237,26 +237,6 @@ 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 - - # 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" - fi - - echo "$_ifname" -} - apply_nm_initrd_generator_timeouts() { local _timeout_conf @@ -304,6 +284,19 @@ _clone_nmconnection() { return 1 } +_match_nmconnection_by_mac() { + local _unique_id _dev _mac _mac_field + + _unique_id=$1 + _dev=$2 + + _mac=$(kdump_get_perm_addr "$_dev") + [[ $_mac != 'not set' ]] || return + _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) +} + # Clone and modify NM connection profiles # # This function makes use of "nmcli clone" to automatically convert ifcfg-* @@ -325,6 +318,10 @@ clone_and_modify_nmconnection() { use_ipv4_or_ipv6 "$_dev" "$_uuid" nmcli connection modify --temporary uuid "$_uuid" connection.wait-device-timeout 60000 &> >(ddebug) + # 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" @@ -528,19 +525,6 @@ kdump_setup_znet() { 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 - fi - echo "$_route" -} - -kdump_get_ip_route_field() { - echo "$1" | sed -n -e "s/^.*\<$2\>\s\+\(\S\+\).*$/\1/p" -} - kdump_get_remote_ip() { local _remote _remote_temp _remote=$(get_remote_host "$1") @@ -557,14 +541,13 @@ kdump_get_remote_ip() { # Collect netifs needed by kdump # $1: destination host kdump_collect_netif_usage() { - local _destaddr _srcaddr _route _netdev kdumpnic + local _destaddr _srcaddr _route _netdev 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") - kdumpnic=$(kdump_setup_ifname "$_netdev") _znet_netdev=$(find_online_znet_device) if [[ -n $_znet_netdev ]]; then @@ -591,8 +574,8 @@ kdump_collect_netif_usage() { echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf" fi - if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpnic.conf ]]; then - echo "kdumpnic=$kdumpnic" > "${initdir}/etc/cmdline.d/60kdumpnic.conf" + 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 diff --git a/kdump-lib-initramfs.sh b/kdump-lib-initramfs.sh index b894507..a8ec3fe 100755 --- a/kdump-lib-initramfs.sh +++ b/kdump-lib-initramfs.sh @@ -162,3 +162,17 @@ is_lvm2_thinp_device() [ -n "$_lvm2_thin_device" ] } + +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" +}