summaryrefslogtreecommitdiff
path: root/meta-yadro/meta-vegman/recipes-yadro/fru/vegman-fru-handler/baseboard-fru-handler.sh
blob: f52acd4a49645be5515ef8c8f595131ed5f25edf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/bin/bash -eu

# SPDX-License-Identifier: Apache-2.0
# Copyright 2020-2021 YADRO

log_msg() {
    echo "$@"
}

log_err() {
    echo "$@" >&2
}

read_hw_mac() {
    local iface="$1"
    cat /sys/class/net/"${iface}"/address 2>/dev/null ||:
}

set_hw_mac() {
    local iface="$1"
    local mac="$2"
    local up=""
    if ip link show dev "${iface}" | grep -q "${iface}:.*\<UP\>" 2>/dev/null; then
        up=true
    fi

    if [ "${up}" = true ]; then
        ip link set dev "${iface}" down ||:
    fi
    ip link set dev "${iface}" address "${mac}" ||:
    if [ "${up}" = true ]; then
        ip link set dev "${iface}" up ||:
    fi
}

set_fw_env_mac() {
    local iface="$1"
    local mac="$2"
    local envname=""
    case "${iface}" in
        eth0)
            envname="ethaddr"
        ;;
        eth1)
            envname="eth1addr"
        ;;
        *)
            return 1
        ;;
    esac
    if ! fw_setenv "$envname" "$mac"; then
        return 1
    fi
}

######## MAIN ########
FRU_DBUS_SERVICE="xyz.openbmc_project.FruDevice"
FRU_DBUS_OBJECT_TEMPLATE="\/xyz.*_Motherboard"
FRU_DBUS_INTERFACE="xyz.openbmc_project.FruDevice"
fru_dbus_object=""

######## Parse D-bus data ########
n=1
while true; do
    fru_dbus_object=$(busctl tree ${FRU_DBUS_SERVICE} 2>/dev/null |
        sed -n "s/^.*\(${FRU_DBUS_OBJECT_TEMPLATE}\).*$/\1/p"
      ) && [ -n "${fru_dbus_object}" ] && break
    if [ ${n} -lt 15 ]; then
        n=$((n+1))
        sleep 1
    else
        log_err "Failed to find baseboard FRU object"
        exit 1
    fi
done

dbusData=$(dbus-send --system --print-reply=literal \
            --dest=${FRU_DBUS_SERVICE} \
            "${fru_dbus_object}" \
            org.freedesktop.DBus.Properties.GetAll \
            string:${FRU_DBUS_INTERFACE} 2>/dev/null ||:)

if [ -z "${dbusData}" ]; then
    log_err "Failed to get data from D-Bus"
    exit 1
fi

# This awk script matches strings 010xyyyyyyyyyyyy, where x is interface index
# and yyyyyyyyyyyy - interface mac address.
# The output would be in form ethx=yy:yy:yy:yy:yy:yy
macsList=$(echo "${dbusData}" | \
    awk '/BOARD_INFO_AM[0-9]+\s+variant\s+010[0-9a-f]{13}/{
        totalMacDigits=12
        singleOctet=2
        offset=4
        printf "eth%s=", substr($3, offset, 1)
        for(i = 1 + offset; i < totalMacDigits + offset; i += singleOctet) {
            printf "%s", substr($3, i, singleOctet)
            if (i <= totalMacDigits + offset - singleOctet) printf ":"
        }
        printf "\n"
    }'||:)

if [ -z "${macsList}" ]; then
    log_err "Failed to get MAC address"
    exit 1
fi

# Get hardware model name from PRODUCT_PRODUCT_NAME
# Examples:
#  'VEGMAN N110 Server' -> 'VEGMAN-N110'
#  'TATLIN.ARCHIVE.XS' -> 'TATLIN-ARCHIVE-XS'
modelName=$(echo "${dbusData}" | \
        awk '/PRODUCT_PRODUCT_NAME\s+variant\s+/{
                if ($3 ~ /^VEGMAN/) {
                    printf "%s-%s", $3, $4
                } else if ($3 ~ /^TATLIN/) {
                    print gensub(/\./, "-", "g", $3)
                }
             }'||:)

serialNumber=$(echo "${dbusData}" | \
     awk '/PRODUCT_SERIAL_NUMBER\s+variant\s+/{print $3}'||:)
if [ -z "${serialNumber}" ]; then
    log_err "Failed to get product Serial Number"
    exit 1
fi

# shellcheck disable=SC1091
source /etc/os-release


######## Check and set MAC addresses ########
retCode=0
IFS='
'
for line in ${macsList} ; do
    ifaceName=$(echo "${line}" | cut -f 1 -d '=' || :)
    macAddr=$(echo "${line}" | cut -f 2- -d '=' || :)
    if [ -n "${ifaceName}" ] && [ -n "${macAddr}" ]; then
        curMacAddr=$(read_hw_mac "${ifaceName}")
        if [ "${macAddr}" != "${curMacAddr}" ] ; then
            log_msg "Changing MAC address for ${ifaceName}: ${curMacAddr} -> ${macAddr}"
            # A factory assigned address was found, and it is newly assigned.
            # Update the active interface and save the new value to the u-boot
            # environment.
            if ! set_hw_mac "${ifaceName}" "${macAddr}"; then
                log_err "Failed to set address"
                retCode=1
            fi
            if ! set_fw_env_mac "${ifaceName}" "${macAddr}"; then
                log_err "Failed to set boot env for ${ifaceName}"
                retCode=1
            fi
        fi
    fi

    [ ${retCode} -eq 0 ] || exit ${retCode}
done


######## Check and set hostname ########
hostname=$(hostname)
if [ "${OPENBMC_TARGET_MACHINE}" = "${hostname}" ] ; then
    hostname="${modelName,,}-${serialNumber}"
    log_msg "Changing hostname to ${hostname}"

    if ! hostnamectl set-hostname "${hostname}-${SN}"; then
        log_err "Failed to set new hostname"
        exit 1
    fi
fi

######## Run optional scripts ########
snmp_handler="/usr/sbin/snmpd-generate-conf.sh"
if [ -x ${snmp_handler} ]; then
    if ! ${snmp_handler} "${modelName}"; then
        log_err "Failed to setup snmp"
    fi
fi