From dbacf3e8dfe55beb31cae7ed1bb135e2fe17a1a8 Mon Sep 17 00:00:00 2001 From: Victor Lowther Date: Wed, 6 Nov 2013 22:39:15 -0600 Subject: [PATCH] Make pxe_mac accurate in two common cases. If we are booting pxe booting using syslinux, and it has IPAPPEND 2 in the boot stanza, then it will append the mac address of the device we are booting from to the kernel parameters where we can get at it pretty easily. If we are booting physical hardware via UEFI over the network, we can rely on the BootCurrent EFI variable to point at the boot entry for the NIC we booted from, which will include the MAC address of that nic. If neither of those cases are in play, we can just fall back to the all-physical-devices-with-links code. This currently uses the Bash 4 support for associative arrays to handle the netboot-in-UEFI case, if needed I can rewrite it to be Bash 3 compatible. Change-Id: I5e50e30c60d6d732a09ab61251cbb9be08bb6113 --- elements/hwdiscovery/init.d/60-hwdiscovery | 55 +++++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/elements/hwdiscovery/init.d/60-hwdiscovery b/elements/hwdiscovery/init.d/60-hwdiscovery index 833f4127..a87aed04 100644 --- a/elements/hwdiscovery/init.d/60-hwdiscovery +++ b/elements/hwdiscovery/init.d/60-hwdiscovery @@ -11,13 +11,54 @@ function ram() { } function pxe_mac() { - # XXX: This is making all sorts of risky assumptions. Firstly that the underlying drivers correctly report link. Secondly that only the primary - # XXX: NIC is wired up. Without a backend service on the DHCP/PXE server which could examine all of our detected MACs, there really is no good - # XXX: way to solve this in Linux. - _info1=$(hwinfo --network|grep -B2 "Link detected: yes"|grep -C1 "HW Address:") - _info2=$(echo "${_info1}"|awk '/Device File: (vlan*|br*)/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}') - _dev=$(echo "${_info1}" | grep "Device File:"|awk -F':' {'print $2'}|tr -d ' ') - _mac=$(echo "${_info2}" | grep "HW Address:"|awk -F'ss:' {'print $2'}|tr -d ' ') + local bootif_re='BOOTIF=([^ ]+)' _mac + if [[ $(cat /proc/cmdline) =~ $bootif_re ]]; then + # If we were booted using pxelinux and its config file has the + # IPAPPEND 2 stanza under the entry we booted from, then pxelinux + # will have appended a BOOTIF argument to the kernel parameters telling + # us what MAC address we are booting with. From that, we can derive the + # boot interface with no problems. + _mac="${BASH_REMATCH[1]//-/:}" + _mac="${_mac#*:}" + elif [[ -d /sys/firmware/efi ]] && which efibootmgr &>/dev/null; then + # Likewise, if we booted via the network while running in UEFI mode, and + # efibootmgr is installed, we can determine the MAC address of the nic we + # booted from. It would be good to have code that can also do this using + # efivars or parsing the stuff under /sys/firmware/efi/efivars directly, + # but that is a trickier thing to do. + local -A boot_entries + local bootent_re='^Boot([0-9]{4})' + local efimac_re='MAC\(([0-9a-f]+)' + local k v current_bootent + while read line; do + k="${line%% *}" + v="${line#* }" + if [[ $k = BootCurrent:* ]]; then + current_bootent="${line##BootCurrent: }" + elif [[ $k =~ $bootent_re ]]; then + boot_entries["${BASH_REMATCH[1]}"]="$v" + fi + done < <(efibootmgr -v) + + if [[ ${boot_entries["$current_bootent"]} =~ $efimac_re ]]; then + _mac='' + for o in 0 2 4 6 8 10; do + _mac+="${BASH_REMATCH[1]:$o:2}:" + done + _mac=${_mac%:} + fi + fi + if [[ ! $_mac ]]; then + # If none of the exact methods worked, fall back on the heuristic + # method and just return the mac addresses of all the interfaces + # that have a link. Hopefully whatever consumes this info is smarter + # than we are. + local _info1 _info2 _dev + _info1=$(hwinfo --network|grep -B2 "Link detected: yes"|grep -C1 "HW Address:") + _info2=$(echo "${_info1}"|awk '/Device File: (vlan*|br*)/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}') + _dev=$(echo "${_info1}" | grep "Device File:"|awk -F':' {'print $2'}|tr -d ' ') + _mac=$(echo "${_info2}" | grep "HW Address:"|awk -F'ss:' {'print $2'}|tr -d ' ') + fi echo $_mac export HW_DISCOVERY_BOOT_IFACE="$_mac" }