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>
Reviewed-by: Thomas Haller <thaller@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
This commit is contained in:
Coiby Xu 2021-09-23 14:25:01 +08:00
parent a65dde2d10
commit 568623e69a
3 changed files with 55 additions and 55 deletions

View File

@ -484,25 +484,28 @@ save_vmcore_dmesg_ssh()
get_host_ip() get_host_ip()
{ {
if is_nfs_dump_target || is_ssh_dump_target; then
kdumpnic=$(getarg kdumpnic=) if ! is_nfs_dump_target && ! is_ssh_dump_target; then
if [ -z "$kdumpnic" ]; then return 0
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
fi 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() read_kdump_confs()

View File

@ -237,26 +237,6 @@ kdump_get_perm_addr() {
fi 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() { apply_nm_initrd_generator_timeouts() {
local _timeout_conf local _timeout_conf
@ -304,6 +284,19 @@ _clone_nmconnection() {
return 1 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 # Clone and modify NM connection profiles
# #
# This function makes use of "nmcli clone" to automatically convert ifcfg-* # 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" use_ipv4_or_ipv6 "$_dev" "$_uuid"
nmcli connection modify --temporary uuid "$_uuid" connection.wait-device-timeout 60000 &> >(ddebug) 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") _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") _tmp_nmconnection_file_path=$_DRACUT_KDUMP_NM_TMP_DIR/$(basename "$_nmconnection_file_path")
cp "$_cloned_nmconnection_file_path" "$_tmp_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" 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() { kdump_get_remote_ip() {
local _remote _remote_temp local _remote _remote_temp
_remote=$(get_remote_host "$1") _remote=$(get_remote_host "$1")
@ -557,14 +541,13 @@ kdump_get_remote_ip() {
# Collect netifs needed by kdump # Collect netifs needed by kdump
# $1: destination host # $1: destination host
kdump_collect_netif_usage() { kdump_collect_netif_usage() {
local _destaddr _srcaddr _route _netdev kdumpnic local _destaddr _srcaddr _route _netdev
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")
kdumpnic=$(kdump_setup_ifname "$_netdev")
_znet_netdev=$(find_online_znet_device) _znet_netdev=$(find_online_znet_device)
if [[ -n $_znet_netdev ]]; then if [[ -n $_znet_netdev ]]; then
@ -591,8 +574,8 @@ kdump_collect_netif_usage() {
echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf" echo "rd.neednet" >> "${initdir}/etc/cmdline.d/50neednet.conf"
fi fi
if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpnic.conf ]]; then if [[ ! -f ${initdir}/etc/cmdline.d/60kdumpip.conf ]]; then
echo "kdumpnic=$kdumpnic" > "${initdir}/etc/cmdline.d/60kdumpnic.conf" echo "kdump_remote_ip=$_destaddr" > "${initdir}/etc/cmdline.d/60kdumpip.conf"
fi fi
if is_ipv6_address "$_srcaddr"; then if is_ipv6_address "$_srcaddr"; then

View File

@ -163,3 +163,17 @@ is_lvm2_thinp_device()
[ -n "$_lvm2_thin_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"
}