#!/bin/bash # Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # shellcheck source=meta-google/recipes-google/ipmi/ipmi-fru-sh/lib.sh source /usr/share/ipmi-fru/lib.sh || exit ipmi_fru_alloc '@EEPROM@' eeprom || exit header=() read_header "$eeprom" header || exit internal_offset=${header[$IPMI_FRU_COMMON_HEADER_INTERNAL_OFFSET_IDX]} if (( internal_offset == 0 )); then echo "Internal offset invalid for eeprom" >&2 exit 1 fi # Our MAC Address configuration lives in the internal area with a format # Offset Data # 0 Version (Always 1) # 1 Type (Always 1 for MAC Address) # 2 Area Length in bytes (Always 32 bytes or 4 IPMI FRU sectors) # 3-8 MAC Address Base Octets # 9 Num Allocate MACs from Base # 10-30 Padding (Always 0xFF) # 31 IPMI FRU Checksum internal=() read_area "$eeprom" "$internal_offset" internal 4 || exit if (( internal[1] != 1 || internal[2] != 32 )); then echo "Not a MAC internal region" >&2 exit 1 fi mac=("${internal[@]:3:6}") num="${internal[9]}" macstr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' "${mac[@]}") echo "Base MAC $macstr num $num" >&2 rc=0 # Pre-Determine if we will miss an allocation due to the number of # addresses the FRU actually supports. # shellcheck disable=SC2190 declare -A num_to_intfs=(@NUM_TO_INTFS@) for key in "${!num_to_intfs[@]}"; do if (( key >= num )); then echo "${num_to_intfs[$key]} at $key is out of range" >&2 rc=1 fi done # Write out each MAC override to the runtime networkd configuration lower=$(((mac[3] << 16) | (mac[4] << 8) | mac[5])) for (( i=0; i 0xffffff )); then echo "MAC assignment too large: ${mac[*]}" >&2 rc=2 break fi for intf in ${num_to_intfs[$i]}; do mac[3]=$(((lower >> 16) & 0xff)) mac[4]=$(((lower >> 8) & 0xff)) mac[5]=$(((lower >> 0) & 0xff)) macstr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' "${mac[@]}") echo "Setting $intf to $macstr" >&2 for override in /run/systemd/network/{00,}-bmc-$intf.network.d; do mkdir -p "$override" printf '[Link]\nMACAddress=%s\n' "$macstr" >"$override"/50-mac.conf done for override in /run/systemd/network/{00,}-bmc-$intf.netdev.d; do mkdir -p "$override" printf '[NetDev]\nMACAddress=%s\n' "$macstr" >"$override"/50-mac.conf done # In case we don't have any interface configs, set the MAC directly # This is safe to apply, as systemd-networkd will always override this # value based on written configs. if ip link show "$intf" >/dev/null 2>&1 && \ ! ip link set dev "$intf" address "$macstr"; then echo "Setting MAC($macstr) on $intf failed" >&2 fi done (( ++lower )) done exit $rc