Initial commit
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
SUMMARY = "ACPI Power/Sleep state daemon to allow host state events"
|
||||
DESCRIPTION = "ACPI Power/Sleep state daemon to allow host state events"
|
||||
GOOGLE_MISC_PROJ = "acpi-power-state-daemon"
|
||||
|
||||
require ../google-misc/google-misc.inc
|
||||
|
||||
inherit pkgconfig systemd
|
||||
|
||||
DEPENDS += " \
|
||||
phosphor-dbus-interfaces \
|
||||
sdbusplus \
|
||||
systemd \
|
||||
"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} = " \
|
||||
acpi-power-state.service \
|
||||
host-s0-state.target \
|
||||
host-s5-state.target \
|
||||
"
|
||||
@@ -0,0 +1,39 @@
|
||||
SUMMARY = "Glome Config"
|
||||
DESCRIPTION = "Glome config file provides a glome config file"
|
||||
PR = "r1"
|
||||
|
||||
# This is required to replace the glome/config that is removed in glome_git.bb
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
# Example Privkey: A0F1D0A0CB254839D04637F567325B850B5174850B129E811F5E203A42CC3B6C
|
||||
GLOME_PUBLIC_KEY ?= "AC11D4582261F2D05CDDE1BD94383393D26C5C269642EE26D7EABD1EADC03C14"
|
||||
GLOME_KEY_VERSION ?= "4"
|
||||
GLOME_URL_PREFIX ?= "http://example-glome-service/"
|
||||
|
||||
SRC_URI = "file://config.in"
|
||||
|
||||
do_install:append() {
|
||||
if [ -z '${GLOME_PUBLIC_KEY}' ]; then
|
||||
echo 'Missing GLOME_PUBLIC_KEY' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -z '${GLOME_KEY_VERSION}' ]; then
|
||||
echo 'Missing GLOME_KEY_VERSION' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -z '${GLOME_URL_PREFIX}' ]; then
|
||||
echo 'Missing GLOME_URL_PREFIX' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed ${WORKDIR}/config.in \
|
||||
-e 's#@PUBLIC_KEY@#${GLOME_PUBLIC_KEY}#' \
|
||||
-e 's#@KEY_VERSION@#${GLOME_KEY_VERSION}#' \
|
||||
-e 's#@URL_PREFIX@#${GLOME_URL_PREFIX}#' \
|
||||
> ${WORKDIR}/config
|
||||
|
||||
install -d ${D}${sysconfdir}/glome
|
||||
install -m 0644 ${WORKDIR}/config ${D}${sysconfdir}/glome
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# This is the configuration file for serial console authentication with glome.
|
||||
# /usr/sbin/glome-login tries to read this file on startup at its canonical
|
||||
# location /etc/glome/config.
|
||||
|
||||
[service]
|
||||
key = @PUBLIC_KEY@
|
||||
key-version = @KEY_VERSION@
|
||||
url-prefix = @URL_PREFIX@
|
||||
@@ -0,0 +1,59 @@
|
||||
SUMMARY = "Glome Login Scripts"
|
||||
DESCRIPTION = "Glome Login Scripts"
|
||||
PR = "r1"
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
GLOME_FALLBACK_SERV ?= ""
|
||||
GLOME_FALLBACK_OBJ ?= ""
|
||||
GLOME_HOSTNAME_SUFFIX ?= ""
|
||||
GLOME_BOARDSN_KEY ?= "bmc-boardsn"
|
||||
|
||||
RDEPENDS:${PN} += "bash"
|
||||
RDEPENDS:${PN} += "glome"
|
||||
RDEPENDS:${PN} += "jq"
|
||||
RDEPENDS:${PN} += "obmc-console"
|
||||
|
||||
SRC_URI += "file://glome-login.sh.in"
|
||||
|
||||
do_install:append() {
|
||||
if [ -z '${GLOME_FALLBACK_SERV}' ]; then
|
||||
echo 'Missing GLOME_FALLBACK_SERV' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z '${GLOME_FALLBACK_OBJ}' ]; then
|
||||
echo 'Missing GLOME_FALLBACK_OBJ' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z '${GLOME_HOSTNAME_SUFFIX}' ]; then
|
||||
echo 'Missing GLOME_HOSTNAME_SUFFIX' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed ${WORKDIR}/glome-login.sh.in \
|
||||
-e 's#@INV_SERV@#${GLOME_FALLBACK_SERV}#' \
|
||||
-e 's#@INV_OBJ@#${GLOME_FALLBACK_OBJ}#' \
|
||||
-e 's#@HOSTNAME_SUFFIX@#${GLOME_HOSTNAME_SUFFIX}#' \
|
||||
-e 's#@BOARDSN_KEY@#${GLOME_BOARDSN_KEY}#' \
|
||||
> ${WORKDIR}/glome-login.sh
|
||||
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 ${WORKDIR}/glome-login.sh ${D}${bindir}
|
||||
}
|
||||
|
||||
# This is an example to override the glome login service in the bbappend for 'prod'
|
||||
#
|
||||
#FILES:${PN}:append:prod = " \
|
||||
# ${systemd_system_unitdir}/serial-to-bmc@.service.d/bmc-login-glome-override.conf \
|
||||
# ${systemd_system_unitdir}/serial-getty@.service.d/bmc-login-glome-override.conf \
|
||||
# "
|
||||
#
|
||||
#do_install:append:prod() {
|
||||
# install -D -m 0644 ${WORKDIR}/bmc-login-glome-override.conf \
|
||||
# ${D}${systemd_system_unitdir}/serial-to-bmc@.service.d/bmc-login-glome-override.conf
|
||||
# install -D -m 0644 ${WORKDIR}/bmc-login-glome-override.conf \
|
||||
# ${D}${systemd_system_unitdir}/serial-getty@.service.d/bmc-login-glome-override.conf
|
||||
#}
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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.
|
||||
set -eo pipefail
|
||||
|
||||
HOSTNAME="$(hostname)"
|
||||
USER="${1?Missing first param: USER (Usually passed by agetty via \\u)}"
|
||||
|
||||
if [[ "$HOSTNAME" =~ ^([^-.]+)[^.]*(.*[.]corp[.]google[.]com)$ ]]; then
|
||||
# for google corp address the suffix must be removed from the name
|
||||
HOSTNAME="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
|
||||
fi
|
||||
|
||||
if [[ "${HOSTNAME}" == *"@HOSTNAME_SUFFIX@" ]]; then
|
||||
# Valid hostname is already set, invoke normal glome
|
||||
exec /usr/sbin/glome-login -M "${HOSTNAME}" "${USER}"
|
||||
fi
|
||||
|
||||
# Get the board serial number from the FRU EEPROM
|
||||
# Service passed in as a parameter would be either inventory-manager or
|
||||
# entity-manager depending on platforms
|
||||
# Path to the FRU EEPROM object has to be passed in as a parameter
|
||||
# If the target platform has neither of them, the fallback mechanism is useless
|
||||
INT="xyz.openbmc_project.Inventory.Decorator.Asset"
|
||||
PART="SerialNumber"
|
||||
BOARDSN="$(busctl get-property -j "@INV_SERV@" "@INV_OBJ@" "${INT}" "${PART}" | jq -r '.data')"
|
||||
|
||||
WARN_MSG="WARNING: Hostname is not set, using Board Serial Number"
|
||||
echo "${WARN_MSG}"
|
||||
echo "${WARN_MSG}" | systemd-cat -t gbmc-glome -p warning
|
||||
exec /usr/sbin/glome-login -M "@BOARDSN_KEY@:${BOARDSN}" "${USER}"
|
||||
@@ -0,0 +1,29 @@
|
||||
SUMMARY = "GLOME Login Client"
|
||||
DESCRIPTION = "GLOME login is first application of the GLOME protocol. It is used to authorize serial console access to Linux machines"
|
||||
PR = "r1"
|
||||
PV = "0.1+git${SRCPV}"
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
|
||||
|
||||
inherit meson pkgconfig
|
||||
|
||||
DEPENDS += " \
|
||||
openssl \
|
||||
glome-config \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
SRC_URI = "git://github.com/google/glome.git;branch=master;protocol=https"
|
||||
SRCREV = "978ad9fb165f1e382c875f2ce08a1fc4f2ddcf1b"
|
||||
|
||||
PACKAGECONFIG ??= ""
|
||||
PACKAGECONFIG[glome-cli] = "-Dglome-cli=true,-Dglome-cli=false"
|
||||
PACKAGECONFIG[pam-glome] = "-Dpam-glome=true,-Dpam-glome=false,libpam"
|
||||
|
||||
EXTRA_OEMESON = "-Dtests=false"
|
||||
|
||||
# remove the default glome config so it can be overridden by `glome-config`
|
||||
do_install:append() {
|
||||
rm -f ${D}${sysconfdir}/glome/config
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
SUMMARY = "Add dev default CA"
|
||||
DESCRIPTION = "Add dev default CA"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
SRC_URI += "file://certs/authority/"
|
||||
|
||||
FILES:${PN} = "${sysconfdir}/ssl/certs/authority/*"
|
||||
|
||||
do_install(){
|
||||
install -d ${D}${sysconfdir}/ssl/certs/authority
|
||||
install -m 0644 -D ${WORKDIR}/certs/authority/* \
|
||||
${D}${sysconfdir}/ssl/certs/authority
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdDCCAlygAwIBAgIBBjANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJUVzEP
|
||||
MA0GA1UEChMGUXVhbnRhMQswCQYDVQQLEwJDQTEQMA4GA1UEAxMHT3BlbkJNQzAe
|
||||
Fw03MDAxMDEwMDAwMDBaFw0zNTEyMzExMjAwMDBaMD0xCzAJBgNVBAYTAlRXMQ8w
|
||||
DQYDVQQKEwZRdWFudGExCzAJBgNVBAsTAkNBMRAwDgYDVQQDEwdPcGVuQk1DMIIB
|
||||
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3IEc5ydpW3grWW2axOYXMgF/
|
||||
Wwj8dXtdbpUwgI44RJS/++szEI07OGKXgn4JakWPCSTzMYrq2IteYx7f+hrqqoc3
|
||||
QZd3tejIGfddGuv8vaAqKlSxaViTjdarRNfa6ARwJao6vQ6XhNy4Phn6mzCSAfGo
|
||||
m1t+JZ3WxMqlsK+NueU30QqKvnYNFmJ7SbwA0htOn8o9WZj5QBTtXP9Clh6aiWyv
|
||||
C6nNYlvPfiMLauc3DwcUEcgzI0slWhxSQJVjLmRrR1GT4A8LdVZfgLrUaZR3hlBm
|
||||
zgtrLJ9BwrdNv4+Q0J/0DEETx4h3SUem5+rZSGaXUvCt+H/VM5sLCRa5+C/oewID
|
||||
AQABo38wfTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTpEhTEnCIZo7dCDFtq
|
||||
UjMRcOI9SDAfBgNVHSMEGDAWgBTpEhTEnCIZo7dCDFtqUjMRcOI9SDALBgNVHQ8E
|
||||
BAMCAb4wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEB
|
||||
CwUAA4IBAQAT+DvCSEZq+nHmvFP05zFS4IN6DikccDZFyG/O06htFLo3NFYxugGI
|
||||
OSDXyR3QzhVsDApIwFsNfYzK7asQMqIBdCTHLQNz8YtW4+lwr/WOijgNMK6H0MqI
|
||||
sisuESpHJgg6XcvfqPkFUBT+sV9ae55QpbvPLalVDZ+JQEyxwfJYnO0AKoepWv/3
|
||||
H5cXTIpgoxD225MeLOu1F5yg3M3DQd2vPmtykgixMDR+dShxR0AFIwfy94XWTZ7K
|
||||
JSp5JysdLcekJ5g2c53CYQCqKIYPhKd/VCt/pERjyAcxHnm/PnmTFRA7ft2aAY82
|
||||
QzkGV2F6gz+GGWjG8cVp3h0T/FF72UFe
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
SUMMARY = "Add default Users"
|
||||
DESCRIPTION = "Add Users"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
EXCLUDE_FROM_WORLD = "1"
|
||||
|
||||
DEPENDS = "bmcweb"
|
||||
DEPENDS += "phosphor-ipmi-host"
|
||||
DEPENDS += "phosphor-user-manager"
|
||||
RDEPENDS:${PN} = "bmcweb"
|
||||
RDEPENDS:${PN} += "phosphor-ipmi-host"
|
||||
RDEPENDS:${PN} += "phosphor-user-manager"
|
||||
|
||||
inherit useradd
|
||||
USERADD_PACKAGES = "${PN}"
|
||||
|
||||
USERADD_PARAM:${PN} = "-m -N -u 1000 -g 100 -s /bin/nologin \
|
||||
-G 'web,redfish,priv-admin' Megapede; "
|
||||
GROUPMEMS_PARAM:${PN} = "-g priv-admin -a root; "
|
||||
GROUPMEMS_PARAM:${PN} += "-g ipmi -a root; "
|
||||
|
||||
ALLOW_EMPTY:${PN} = "1"
|
||||
@@ -0,0 +1,26 @@
|
||||
SUMMARY = "Google BIOS Public Keys"
|
||||
DESCRIPTION = "Google BIOS Public Keys"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
FILESEXTRAPATHS:prepend:gbmc := "${THISDIR}/${PN}:"
|
||||
|
||||
SRC_URI:append:gbmc = " \
|
||||
file://platforms_secure.pem \
|
||||
file://platforms_bringup.pem \
|
||||
"
|
||||
|
||||
|
||||
FILES:${PN} += "${datadir}/google-bios-key/platforms_secure.pem"
|
||||
FILES:${PN} += "${datadir}/google-bios-key/platforms_bringup.pem"
|
||||
FILES:${PN} += "${datadir}/platforms_secure.pem"
|
||||
FILES:${PN} += "${datadir}/platforms_bringup.pem"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${datadir}/google-bios-key
|
||||
install -m 0644 ${WORKDIR}/platforms_secure.pem ${D}${datadir}/google-bios-key
|
||||
install -m 0644 ${WORKDIR}/platforms_bringup.pem ${D}${datadir}/google-bios-key
|
||||
|
||||
ln -s -r ${D}${datadir}/google-bios-key/platforms_secure.pem ${D}${datadir}/platforms_secure.pem
|
||||
ln -s -r ${D}${datadir}/google-bios-key/platforms_bringup.pem ${D}${datadir}/platforms_bringup.pem
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq1licj5L+p5orm2eQsjW
|
||||
7z1L5As2q0ZbyFtE/xeH/8NAbKfTA1LSKiqElcPTM47oFDixGtCm7bubcClWT8Uq
|
||||
Ol6t4CITlgRLFPP06z63mnE83EKj1ZBTATgtO+PN1P/RrQXp0pCPy0AFYtWZPT4J
|
||||
GzxACBwVI/XEuUnCOG4ErXLfgfPZadOMUmP9X5pXeyBgN/al0vThIVpQ7DUix6jd
|
||||
awYd2AwM1TG9qRX1Fmlsut9zUGDoqEOCAdIgx5z9GOTfwzbIg1NWk12iLQyufJ4P
|
||||
FAa4a5QVZYTKcDUNYadx7Qwg/gNspiAIdtB/1ORz1ew1d1csCHqUZcgkCwtaqMYg
|
||||
ZiQ6+7tpJY0vnWyaNXcylOvmZjOlovV3i5NUJ/r74bDC8U+5XKH3ZSmhA6AsnA54
|
||||
QnNHLgsnG89JvfBP2c9UJqb49sw6VkEE3Y8lc134QBaLU3N3LmRVmM4zzPRGbbEK
|
||||
+nmZtBztbKiSHTqMoYGCY5aN1peQdzgNYk5P8mnVWzAIh5y1MzxkEVeu82/zCj+/
|
||||
T54D3jS+a/jxAGnUUmTMYsOYXNqJsPKz36qvrFLstSjrjHVEZjniaetjAuWtVGsO
|
||||
DziPDyywN14iIeR5HdNpqeJ6mCZnY2rLtBzIZRK/JK0LpCvqdEmqg2u/J2Vx2ClE
|
||||
DnNnPSr8XSpsFkaxGYyFjEUCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1,14 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzCYi0R3IiNenOlVNlpOC
|
||||
mIZ/0nq6OGS5Dt1Yex5nr7/bIr+Phk7mct+V7gMJzfdyCOI3n2S2sGDWADUNfvDJ
|
||||
LQgV4xOfoUwhzQ292cp2UFUrPblfZaz0C5x7BRVtj7yfBp8FRFVSpZTNI6QjEQ6m
|
||||
JxVh5C8CYjdQQJLz+wayVZTk72z0iaSBdua+eZYrAc3+ckTvTWJ9V7yO40iyJOXQ
|
||||
ixxHo/p49oHoNp4+q0a6DYYmjka6MESeFbbkND5PkyNV4+vAbgtzkoGnnutk+zQ3
|
||||
K374d9+aOqXlbLBXAUaNkfnF1XjUYQFLrNkFbvOqYura1mBxWuz/OIAfbWxQltzo
|
||||
6cYl0YNw7zbHzSwiTPvt31wxg9EqqIV7QD4hXLAgoclJIK5vhUqIbn3kjSwOv2Rv
|
||||
MQ17wLeCkYaxL4Ovscx6lDnOw+Y76KGia5zky0GvidjaDgzUZTt46/uOtjxxXy5k
|
||||
KhDwqs1QoU0LKBvJL8O7bYj6t0LLQTsI2UW9szVGGsiKB3l0SfIzfvz6eNNng7Uf
|
||||
T9zLPW9jq0BGG61KiYK+Dy/0JwauPub3WzcZwSXnl1OCMLD90HIA2/YsFtfE+mm/
|
||||
Wlta+cR3REHd//DiRlkT59K0H5H8JBrJKhkAVi/gzqoAYhLAOj9irWzsZ2Assm74
|
||||
oa3/lWlmVsKQTAGOCQFeAHsCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1,14 @@
|
||||
HOMEPAGE = "http://github.com/openbmc/google-misc"
|
||||
PR = "r1"
|
||||
PV = "1.0+git${SRCPV}"
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://../../LICENSE;md5=34400b68072d710fecd0a2940a0d1658"
|
||||
|
||||
SRC_URI += "git://github.com/openbmc/google-misc;branch=master;protocol=https"
|
||||
SRCREV = "f8bb4779279d8f4e054d9601fc508598b2ba3007"
|
||||
|
||||
S = "${WORKDIR}/git/subprojects/${GOOGLE_MISC_PROJ}"
|
||||
inherit meson pkgconfig
|
||||
|
||||
EXTRA_OEMESON += "-Dwerror=false"
|
||||
@@ -0,0 +1,249 @@
|
||||
#!/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.
|
||||
|
||||
# This is intended to be used as a library for managing gpio line values.
|
||||
# Executing this directly will do nothing.
|
||||
[ -n "${gpio_ctrl_init-}" ] && return
|
||||
|
||||
# Map names of GPIOs to GPIO number
|
||||
# This maps a schematic name to a gpiochip and line at a specific offset
|
||||
declare -A GPIO_NAMES_TO_SCM=(
|
||||
# Examples
|
||||
#['SYS_RESET_N']='label=/pinctrl@f0800000/gpio@f0012000 21'
|
||||
#['PWRBTN_N']='label=/pinctrl@f0800000/gpio@f0012000 23'
|
||||
#['PCH_SLP_S5_R_N']='of_node=/ahb/apb/i2c@8e000/cpu_seq@6b 9'
|
||||
#['PCH_PWRGOOD_R']='of_node=/ahb/apb/i2c@8e000/cpu_seq@6b 6'
|
||||
)
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# named GPIOs
|
||||
shopt -s nullglob
|
||||
for conf in /usr/share/gpio-ctrl/conf.d/*.sh; do
|
||||
# shellcheck source=/dev/null
|
||||
source "$conf"
|
||||
done
|
||||
|
||||
declare -A gpio_sysfs_lookup_cache=()
|
||||
declare -A gpio_lookup_cache=()
|
||||
|
||||
declare -A gpio_init=()
|
||||
|
||||
##################################################
|
||||
# Looks up the sysfs GPIO number
|
||||
# Arguments:
|
||||
# $1: GPIO name
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
# stdout: The GPIO number
|
||||
##################################################
|
||||
gpio_name_to_num() {
|
||||
local name="$1"
|
||||
|
||||
if [ -n "${gpio_lookup_cache["$name"]+1}" ]; then
|
||||
echo "${gpio_lookup_cache["$name"]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local scm="${GPIO_NAMES_TO_SCM["$name"]-}"
|
||||
if [ -z "$scm" ]; then
|
||||
echo "Missing gpio definition: $name" >&2
|
||||
return 1
|
||||
fi
|
||||
local id="${scm% *}"
|
||||
local type="${id%=*}"
|
||||
local val="${id#*=}"
|
||||
local offset="${scm#* }"
|
||||
|
||||
local sysfs
|
||||
if [ -n "${gpio_sysfs_lookup_cache["$id"]+1}" ]; then
|
||||
sysfs="${gpio_sysfs_lookup_cache["$id"]}"
|
||||
else
|
||||
case "$type" in
|
||||
label)
|
||||
if ! sysfs="$(grep -xl "$val" /sys/class/gpio/gpiochip*/label)"; then
|
||||
echo "Failed to find gpiochip: $val" >&2
|
||||
return 1
|
||||
fi
|
||||
sysfs="${sysfs%/label}"
|
||||
;;
|
||||
of_node)
|
||||
for sysfs in $(echo /sys/class/gpio/gpiochip*); do
|
||||
local link
|
||||
# Ignore errors because not all devices have of_nodes
|
||||
link="$(readlink -f "$sysfs/device/of_node" 2>/dev/null)" || continue
|
||||
[ "${link#/sys/firmware/devicetree/base}" = "$val" ] && break
|
||||
sysfs=
|
||||
done
|
||||
if [ -z "$sysfs" ]; then
|
||||
echo "Failed to find gpiochip: $val" >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Invalid GPIO type $type" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
gpio_sysfs_lookup_cache["$id"]="$sysfs"
|
||||
fi
|
||||
|
||||
local ngpio
|
||||
ngpio=$(<"$sysfs"/ngpio)
|
||||
if (( ngpio <= offset )); then
|
||||
echo "$name with gpiochip $sysfs only has $ngpio but wants $offset" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
gpio_lookup_cache["$name"]=$(( $(<"$sysfs"/base) + offset ))
|
||||
echo "${gpio_lookup_cache["$name"]}"
|
||||
}
|
||||
|
||||
|
||||
##################################################
|
||||
# Populates the GPIO lookup cache
|
||||
# Most calls to gpio_name_to_num that would
|
||||
# normally cache the sysfs lookups for gpios run
|
||||
# inside subshells. This prevents them from
|
||||
# populating a global cache and greatly speeding
|
||||
# up future lookups. This call allows scripts to
|
||||
# populate the cache prior to looking up gpios.
|
||||
##################################################
|
||||
gpio_build_cache() {
|
||||
local timeout="${1-0}"
|
||||
shift
|
||||
local gpios=("$@")
|
||||
|
||||
if (( ${#gpios[@]} == 0 )); then
|
||||
gpios=("${!GPIO_NAMES_TO_SCM[@]}")
|
||||
fi
|
||||
|
||||
local deadline=$(( timeout + SECONDS ))
|
||||
local name
|
||||
for name in "${gpios[@]}"; do
|
||||
while true; do
|
||||
gpio_name_to_num "$name" >/dev/null && break
|
||||
if (( deadline <= SECONDS )); then
|
||||
echo "Timed out building gpio cache" >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Initializes the gpio state
|
||||
# This operation is idempotent and can be applied
|
||||
# repeatedly to the same gpio. It will make sure the
|
||||
# gpio ends up in the initialized state even if it
|
||||
# was.
|
||||
# Arguments:
|
||||
# $1: GPIO name
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
##################################################
|
||||
gpio_init_() {
|
||||
local name="$1"
|
||||
local num="$2"
|
||||
|
||||
if [ -n "${gpio_init["$name"]+1}" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -e "/sys/class/gpio/gpio$num" ]; then
|
||||
if ! echo "$num" >'/sys/class/gpio/export'; then
|
||||
echo "Failed to export $name gpio$num" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
local active_low=0
|
||||
if [[ "${name%_N}" != "$name" ]]; then
|
||||
active_low=1
|
||||
fi
|
||||
if ! echo "$active_low" >"/sys/class/gpio/gpio$num/active_low"; then
|
||||
echo "Failed to set active_low for $name gpio$num" >&2
|
||||
return 1
|
||||
fi
|
||||
gpio_init["$name"]=1
|
||||
}
|
||||
gpio_init() {
|
||||
local name="$1"
|
||||
|
||||
# Ensure the cache is updated by not running in a subshell
|
||||
gpio_name_to_num "$name" >/dev/null || return
|
||||
|
||||
gpio_init_ "$name" "$(gpio_name_to_num "$name")"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Sets the output GPIO value.
|
||||
# Arguments:
|
||||
# $1: GPIO name
|
||||
# $2: GPIO value, "1" or "0"
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
##################################################
|
||||
gpio_set_value_() {
|
||||
local name="$1"
|
||||
local num="$2"
|
||||
local val="$3"
|
||||
|
||||
gpio_init_ "$name" "$num" || return
|
||||
if ! echo out >"/sys/class/gpio/gpio$num/direction"; then
|
||||
echo "Failed to set output for $name gpio$num" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! echo "$val" >"/sys/class/gpio/gpio$num/value"; then
|
||||
echo "Failed to set $name gpio$num = $val" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
gpio_set_value() {
|
||||
local name="$1"
|
||||
local val="$2"
|
||||
|
||||
# Ensure the cache is updated by not running in a subshell
|
||||
gpio_name_to_num "$name" >/dev/null || return
|
||||
|
||||
gpio_set_value_ "$name" "$(gpio_name_to_num "$name")" "$val"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Get GPIO value
|
||||
# Arguments:
|
||||
# $1: GPIO name
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
# stdout: The value of the gpio
|
||||
##################################################
|
||||
gpio_get_value_() {
|
||||
local name="$1"
|
||||
local num="$2"
|
||||
|
||||
gpio_init_ "$name" "$num" || return
|
||||
if ! cat "/sys/class/gpio/gpio$num/value"; then
|
||||
echo "Failed to get $name gpio$num value" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
gpio_get_value() {
|
||||
local name="$1"
|
||||
|
||||
# Ensure the cache is updated by not running in a subshell
|
||||
gpio_name_to_num "$name" >/dev/null || return
|
||||
|
||||
gpio_get_value_ "$name" "$(gpio_name_to_num "$name")"
|
||||
}
|
||||
|
||||
gpio_ctrl_init=1
|
||||
@@ -0,0 +1,14 @@
|
||||
SUMMARY = "GPIO control library for bash scripts"
|
||||
DESCRIPTION = "GPIO control library for bash scripts."
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
PR = "r1"
|
||||
|
||||
SRC_URI += "file://lib.sh"
|
||||
|
||||
RDEPENDS:${PN} = "bash"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${datadir}/gpio-ctrl
|
||||
install -m 0755 ${WORKDIR}/lib.sh ${D}${datadir}/gpio-ctrl/
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Ensure host is off on clean AC cycle
|
||||
Before=host-poweron.service
|
||||
Before=firmware-updates-pre.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_ensure_off.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Powercycle host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=DONT_STOP_WATCHDOG=1
|
||||
ExecStart=/usr/bin/host_powercycle.sh
|
||||
@@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description=Powercycle host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_powercycle.sh
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Power off host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=DONT_STOP_WATCHDOG=1
|
||||
ExecStart=/usr/bin/host_poweroff.sh
|
||||
@@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description=Power off host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_poweroff.sh
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Power on host
|
||||
After=firmware-updates.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_poweron.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Cold Reset Host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=DONT_STOP_WATCHDOG=1
|
||||
ExecStart=/usr/bin/host_reset.sh cold
|
||||
@@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description=Cold Reset Host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_reset.sh cold
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Warm Reset Host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=DONT_STOP_WATCHDOG=1
|
||||
ExecStart=/usr/bin/host_reset.sh warm
|
||||
@@ -0,0 +1,6 @@
|
||||
[Unit]
|
||||
Description=Warm Reset Host
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/host_reset.sh warm
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/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.
|
||||
|
||||
if ! was_ac_reset.sh; then
|
||||
echo "Not a tray reset, ignoring" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Powering off the host" >&2
|
||||
host_poweroff.sh
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/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/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-host-pwr/lib.sh || exit
|
||||
|
||||
gpio_build_cache 10 "$HOST_GPIO_PGOOD" || exit 255
|
||||
pgood="$(gpio_get_value "$HOST_GPIO_PGOOD")" || exit 255
|
||||
echo "HOST_PGOOD=$pgood" >&2
|
||||
(( pgood == 0 ))
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/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/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-host-pwr/lib.sh || exit
|
||||
gpio_build_cache 10 "$HOST_GPIO_PGOOD" "$HOST_GPIO_PWR_BTN" || exit
|
||||
|
||||
rc=0
|
||||
host_poweroff.sh || rc=$?
|
||||
# We want to ensure we aren't too quickly bouncing the power button
|
||||
sleep 0.5
|
||||
host_poweron.sh || rc=$?
|
||||
exit $rc
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/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/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-host-pwr/lib.sh || exit
|
||||
|
||||
gpio_build_cache 10 "$HOST_GPIO_PGOOD" "$HOST_GPIO_PWR_BTN" || exit
|
||||
gpio_init "$HOST_GPIO_PGOOD" || exit
|
||||
|
||||
# Set the power status LED
|
||||
if [ -n "$HOST_LED_PWR" ]; then
|
||||
echo 'none' > /sys/class/leds/"$HOST_LED_PWR"/trigger || true
|
||||
echo '0' > /sys/class/leds/"$HOST_LED_PWR"/brightness || true
|
||||
fi
|
||||
|
||||
# Ensure the watchdog is no longer going to run
|
||||
host_pwr_stop_watchdog || true
|
||||
|
||||
# We don't want to do anything if the machine is already off
|
||||
pgood="$(gpio_get_value "$HOST_GPIO_PGOOD")" || exit
|
||||
if (( pgood == 0 )); then
|
||||
echo 'Host is already off, doing nothing' >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do a long push of the button if PGOOD
|
||||
echo 'Stopping host power' >&2
|
||||
rc=0
|
||||
gpio_set_value "$HOST_GPIO_PWR_BTN" 1 || rc=$?
|
||||
|
||||
# Loop until we realize that host power is off
|
||||
# Limit the loop count to 10 seconds as we should never
|
||||
# have to wait this long for poweroff
|
||||
s=$SECONDS
|
||||
while true; do
|
||||
if ! pgood="$(gpio_get_value "$HOST_GPIO_PGOOD")"; then
|
||||
rc=1
|
||||
break
|
||||
fi
|
||||
if (( pgood == 0 )); then
|
||||
echo 'Host is now off' >&2
|
||||
break
|
||||
fi
|
||||
if (( SECONDS - s > 10 )); then
|
||||
echo 'Poweroff timed out, terminating' >&2
|
||||
rc=2
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
gpio_set_value "$HOST_GPIO_PWR_BTN" 0 || rc=$?
|
||||
|
||||
exit $rc
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/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/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-host-pwr/lib.sh || exit
|
||||
|
||||
gpio_build_cache 10 "$HOST_GPIO_PGOOD" "$HOST_GPIO_PWR_BTN" || exit
|
||||
gpio_init "$HOST_GPIO_PGOOD" || exit
|
||||
|
||||
# Set the power status LED
|
||||
if [ -n "$HOST_LED_PWR" ]; then
|
||||
echo 'none' > /sys/class/leds/"$HOST_LED_PWR"/trigger || true
|
||||
echo '255' > /sys/class/leds/"$HOST_LED_PWR"/brightness || true
|
||||
fi
|
||||
|
||||
# Ensure the watchdog is available before the host starts
|
||||
host_pwr_start_watchdog || true
|
||||
|
||||
# We don't want to do anything if the machine is already on
|
||||
pgood="$(gpio_get_value "$HOST_GPIO_PGOOD")" || exit
|
||||
if (( pgood == 1 )); then
|
||||
echo 'Host is already running, doing nothing' >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Do a quick push of the button if PGOOD
|
||||
echo "Starting host power" >&2
|
||||
rc=0
|
||||
gpio_set_value "$HOST_GPIO_PWR_BTN" 1 || rc=$?
|
||||
sleep 0.1
|
||||
gpio_set_value "$HOST_GPIO_PWR_BTN" 0 || rc=$?
|
||||
|
||||
# Loop until we realize that host power is on
|
||||
# Limit the loop count to 10 seconds as we should never
|
||||
# have to wait this long for poweroff
|
||||
s=$SECONDS
|
||||
while true; do
|
||||
if ! pgood="$(gpio_get_value "$HOST_GPIO_PGOOD")"; then
|
||||
rc=1
|
||||
break
|
||||
fi
|
||||
if (( pgood == 1 )); then
|
||||
echo 'Host is now on' >&2
|
||||
break
|
||||
fi
|
||||
if (( SECONDS - s > 10 )); then
|
||||
echo 'Poweron timed out, terminating' >&2
|
||||
rc=2
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
exit $rc
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/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/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-host-pwr/lib.sh || exit
|
||||
|
||||
if [[ "${1-}" == "warm" ]]; then
|
||||
rst_txt='WARM' >&2
|
||||
rst_gpio="$HOST_GPIO_WARM_RESET"
|
||||
else
|
||||
rst_txt='COLD' >&2
|
||||
rst_gpio="$HOST_GPIO_COLD_RESET"
|
||||
fi
|
||||
|
||||
gpio_build_cache 10 "$rst_gpio" || exit
|
||||
|
||||
# Do a quick push of the button if PGOOD
|
||||
echo "Issuing $rst_txt reset" >&2
|
||||
rc=0
|
||||
gpio_set_value "$rst_gpio" 1 || rc=$?
|
||||
sleep 0.1
|
||||
gpio_set_value "$rst_gpio" 0 || rc=$?
|
||||
|
||||
# Make sure the watchdog is stopped while the host is in reset
|
||||
# and can't possibly restart it.
|
||||
host_pwr_stop_watchdog || true
|
||||
|
||||
exit $rc
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/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.
|
||||
|
||||
# This is intended to be used as a library for managing gpio line values.
|
||||
# Executing this directly will do nothing.
|
||||
[ -n "${host_pwr_init-}" ] && return
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/gpio/gpio-ctrl/lib.sh
|
||||
source /usr/share/gpio-ctrl/lib.sh || exit
|
||||
|
||||
# Read by the tooling to determine if the machine is powered on or off
|
||||
# shellcheck disable=SC2034
|
||||
HOST_GPIO_PGOOD='unset'
|
||||
# Set according to whether the host is powered on or off
|
||||
# shellcheck disable=SC2034
|
||||
HOST_LED_PWR=''
|
||||
# Written by the tooling to assert the power button
|
||||
# shellcheck disable=SC2034
|
||||
HOST_GPIO_PWR_BTN='unset'
|
||||
# Written by the tooling to assert a cold reset
|
||||
# shellcheck disable=SC2034
|
||||
HOST_GPIO_COLD_RESET='unset'
|
||||
# Written by the tooling to assert a warm reset
|
||||
# shellcheck disable=SC2034
|
||||
HOST_GPIO_WARM_RESET='unset'
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# named GPIOs
|
||||
shopt -s nullglob
|
||||
for conf in /usr/share/gpio-host-pwr/conf.d/*.sh; do
|
||||
# shellcheck source=/dev/null
|
||||
source "$conf"
|
||||
done
|
||||
|
||||
##################################################
|
||||
# Stop the host watchdog
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
##################################################
|
||||
host_pwr_stop_watchdog() {
|
||||
# Check to see if we can stop the watchdog safely
|
||||
# We don't want to stop if we are called from the watchdog itself
|
||||
if [ -n "${DONT_STOP_WATCHDOG-}" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo 'Stopping the host watchdog' >&2
|
||||
systemctl stop phosphor-watchdog@host0
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Start the host watchdog
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
##################################################
|
||||
host_pwr_start_watchdog() {
|
||||
echo 'Starting the host watchdog' >&2
|
||||
systemctl start phosphor-watchdog@host0
|
||||
}
|
||||
|
||||
host_pwr_init=1
|
||||
@@ -0,0 +1,57 @@
|
||||
SUMMARY = "GPIO based powercontrol for a host system"
|
||||
DESCRIPTION = "GPIO based powercontrol for a host system."
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
RDEPENDS:${PN} += " \
|
||||
bash \
|
||||
gpio-ctrl \
|
||||
"
|
||||
|
||||
SRC_URI += " \
|
||||
file://host-ensure-off.service \
|
||||
file://host-powercycle-watchdog.service \
|
||||
file://host-powercycle.service \
|
||||
file://host-poweroff-watchdog.service \
|
||||
file://host-poweroff.service \
|
||||
file://host-poweron.service \
|
||||
file://host-reset-cold-watchdog.service \
|
||||
file://host-reset-cold.service \
|
||||
file://host-reset-warm-watchdog.service \
|
||||
file://host-reset-warm.service \
|
||||
file://host_ensure_off.sh \
|
||||
file://host_isoff.sh \
|
||||
file://host_powercycle.sh \
|
||||
file://host_poweroff.sh \
|
||||
file://host_poweron.sh \
|
||||
file://host_reset.sh \
|
||||
file://lib.sh \
|
||||
"
|
||||
|
||||
SYSTEMD_PACKAGES = "${PN}"
|
||||
SYSTEMD_SERVICE:${PN} += " \
|
||||
host-reset-cold.service \
|
||||
host-reset-cold-watchdog.service \
|
||||
host-reset-warm.service \
|
||||
host-reset-warm-watchdog.service \
|
||||
host-ensure-off.service \
|
||||
host-powercycle.service \
|
||||
host-powercycle-watchdog.service \
|
||||
host-poweroff.service \
|
||||
host-poweroff-watchdog.service \
|
||||
host-poweron.service \
|
||||
"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 ${WORKDIR}/host_*.sh ${D}${bindir}/
|
||||
|
||||
install -d ${D}${datadir}/gpio-host-pwr
|
||||
install -m 0755 ${WORKDIR}/lib.sh ${D}${datadir}/gpio-host-pwr/
|
||||
|
||||
install -d ${D}${systemd_system_unitdir}
|
||||
install -m 0644 ${WORKDIR}/*.service ${D}${systemd_system_unitdir}/
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/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.
|
||||
|
||||
##################################################
|
||||
# Stop the host watchdog
|
||||
# Return:
|
||||
# 0 if success, non-zero if error
|
||||
##################################################
|
||||
stop_host_watchdog() {
|
||||
if (( $# != 0 )); then
|
||||
echo 'Usage: stop_host_watchdog' >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local srv='xyz.openbmc_project.Watchdog'
|
||||
local obj='/xyz/openbmc_project/watchdog/host0'
|
||||
local intf='xyz.openbmc_project.State.Watchdog'
|
||||
local method='Enabled'
|
||||
local args=('b' 'false')
|
||||
busctl set-property "${srv}" "${obj}" "${intf}" "${method}" "${args[@]}"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
SUMMARY = "Watchdog Shell Library"
|
||||
DESCRIPTION = "Watchdog Shell Library"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
SRC_URI += " \
|
||||
file://libwatchdog.sh \
|
||||
"
|
||||
|
||||
RDEPENDS:${PN} = "bash"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${libexecdir}
|
||||
install -m 0755 ${WORKDIR}/libwatchdog.sh ${D}${libexecdir}/
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
SUMMARY = "Google i2c OEM commands"
|
||||
DESCRIPTION = "Google i2c OEM commands"
|
||||
HOMEPAGE = "https://github.com/openbmc/google-ipmi-i2c"
|
||||
PR = "r1"
|
||||
PV = "0.1+git${SRCPV}"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
|
||||
|
||||
inherit meson pkgconfig
|
||||
|
||||
DEPENDS += "phosphor-ipmi-host"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
SRC_URI = "git://github.com/openbmc/google-ipmi-i2c;branch=master;protocol=https"
|
||||
SRCREV = "6c84db51ea55f247e1f8054b62fff3b66b8017b7"
|
||||
|
||||
FILES:${PN}:append = " ${libdir}/ipmid-providers"
|
||||
FILES:${PN}:append = " ${libdir}/host-ipmid"
|
||||
FILES:${PN}:append = " ${libdir}/net-ipmid"
|
||||
|
||||
HOSTIPMI_PROVIDER_LIBRARY += "libi2ccmds.so"
|
||||
@@ -0,0 +1,38 @@
|
||||
SUMMARY = "Google Sys OEM commands"
|
||||
DESCRIPTION = "Google Sys OEM commands"
|
||||
HOMEPAGE = "https://github.com/openbmc/google-ipmi-sys"
|
||||
PR = "r1"
|
||||
PV = "0.1+git${SRCPV}"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
|
||||
|
||||
inherit meson pkgconfig systemd
|
||||
|
||||
DEPENDS += " \
|
||||
nlohmann-json \
|
||||
phosphor-dbus-interfaces \
|
||||
phosphor-logging \
|
||||
phosphor-ipmi-host \
|
||||
sdbusplus \
|
||||
systemd \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}/git"
|
||||
SRC_URI = "git://github.com/openbmc/google-ipmi-sys;branch=master;protocol=https"
|
||||
SRCREV = "15d4d21c091cd57a0e25888a8d360ba3a32965ff"
|
||||
|
||||
FILES:${PN} += "${libdir}/ipmid-providers"
|
||||
|
||||
SYSTEMD_PACKAGES = "${PN}"
|
||||
SYSTEMD_SERVICE:${PN} += " \
|
||||
gbmc-bare-metal-active.target \
|
||||
gbmc-host-poweroff.target \
|
||||
gbmc-psu-hardreset.target \
|
||||
gbmc-psu-hardreset-pre.target \
|
||||
gbmc-psu-hardreset-time.service \
|
||||
"
|
||||
|
||||
EXTRA_OEMESON += "-Dtests=disabled"
|
||||
|
||||
CXXFLAGS:append:gbmc = '${@"" if not d.getVar("GBMC_NCSI_IF_NAME") else \
|
||||
" -DNCSI_IPMI_CHANNEL=1 -DNCSI_IF_NAME=" + d.getVar("GBMC_NCSI_IF_NAME")}'
|
||||
@@ -0,0 +1,16 @@
|
||||
SUMMARY = "Shell functions for manipulating IPMI formatted EEPROMs"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
|
||||
SRC_URI += "file://lib.sh"
|
||||
S = "${WORKDIR}"
|
||||
|
||||
DATA = "${datadir}/ipmi-fru"
|
||||
FILES:${PN} += "${DATA}"
|
||||
|
||||
do_install:append() {
|
||||
install -d -m0755 ${D}${DATA}
|
||||
install -m0644 lib.sh ${D}${DATA}/
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
#!/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.
|
||||
|
||||
[ -n "${ipmi_fru_init-}" ] && return
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_COMMON_HEADER_INTERNAL_OFFSET_IDX=1
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_COMMON_HEADER_CHASSIS_OFFSET_IDX=2
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_COMMON_HEADER_BOARD_OFFSET_IDX=3
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_COMMON_HEADER_PRODUCT_OFFSET_IDX=4
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_COMMON_HEADER_MULTI_RECORD_OFFSET_IDX=5
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_AREA_HEADER_SIZE_IDX=1
|
||||
# shellcheck disable=SC2034
|
||||
IPMI_FRU_CHECKSUM_IDX=-1
|
||||
|
||||
offset_1bw() {
|
||||
local addr="$1"
|
||||
local off="$2"
|
||||
local extra="${3-0}"
|
||||
echo "w$((1+extra))@$addr $(( off & 0xff ))"
|
||||
}
|
||||
|
||||
offset_2bw() {
|
||||
local addr="$1"
|
||||
local off="$2"
|
||||
local extra="${3-0}"
|
||||
echo "w$((2+extra))@$addr $(( (off >> 8) & 0xff )) $(( off & 0xff ))"
|
||||
}
|
||||
|
||||
of_name_to_eeproms() {
|
||||
local names
|
||||
if ! names="$(grep -xl "$1" /sys/bus/i2c/devices/*/of_node/name)"; then
|
||||
echo "Failed to find eeproms with of_name '$1'" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "${names//of_node\/name/eeprom}"
|
||||
}
|
||||
|
||||
of_name_to_eeprom() {
|
||||
local eeproms
|
||||
eeproms="$(of_name_to_eeproms "$1")" || return
|
||||
if (( "$(echo "$eeproms" | wc -l)" != 1 )); then
|
||||
echo "Got more than one eeprom for '$1': $eeproms" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "$eeproms"
|
||||
}
|
||||
|
||||
# Each element is a `filename`
|
||||
declare -A IPMI_FRU_EEPROM_FILE=()
|
||||
# Each element is a `bus` + `addr` + `offset_bytes_func`
|
||||
declare -A IPMI_FRU_EEPROM_BUSADDR=()
|
||||
|
||||
ipmi_fru_device_alloc() {
|
||||
local fdn="$1"
|
||||
local idx="$2"
|
||||
|
||||
local json
|
||||
json="$(busctl -j call xyz.openbmc_project.FruDevice \
|
||||
/xyz/openbmc_project/FruDevice/"$fdn" org.freedesktop.DBus.Properties \
|
||||
GetAll s xyz.openbmc_project.FruDevice)" || return 80
|
||||
|
||||
local jqq='.data[0] | (.BUS.data | tostring) + " " + (.ADDRESS.data | tostring)'
|
||||
local busaddr
|
||||
# shellcheck disable=SC2207
|
||||
busaddr=($(echo "$json" | jq -r "$jqq")) || return
|
||||
|
||||
# FRU 0 is hardcoded and FruDevice does not report the correct bus for it
|
||||
# Hardcode a workaround for this specifically known bus
|
||||
if (( busaddr[0] == 0 && busaddr[1] == 0 )); then
|
||||
IPMI_FRU_EEPROM_FILE["$idx"]=/etc/fru/baseboard.fru.bin
|
||||
else
|
||||
local offset_bw=offset_2bw
|
||||
local last=0
|
||||
local rsp=0x100
|
||||
local start=$SECONDS
|
||||
# Query the FRU multiple times to ensure the return value is stabilized
|
||||
while (( last != rsp )); do
|
||||
# It shouldn't take > 0.1s to stabilize, limit instability
|
||||
if (( SECONDS - start >= 10 )); then
|
||||
echo "Timed out determining offset for ${busaddr[0]}@${busaddr[1]}" >&2
|
||||
return 1
|
||||
fi
|
||||
last=$rsp
|
||||
# shellcheck disable=SC2046
|
||||
rsp=$(i2ctransfer -f -y "${busaddr[0]}" $(offset_1bw "${busaddr[1]}" 0) r1) || return
|
||||
done
|
||||
# FRUs never start with 0xff bytes, so we can figure out addressing mode
|
||||
if (( rsp != 0xff )); then
|
||||
offset_bw=offset_1bw
|
||||
fi
|
||||
IPMI_FRU_EEPROM_BUSADDR["$idx"]="${busaddr[*]} $offset_bw"
|
||||
fi
|
||||
}
|
||||
|
||||
ipmi_fru_alloc() {
|
||||
local name="$1"
|
||||
local -n ret="$2"
|
||||
|
||||
# Pick the first free index to return as the allocated entry
|
||||
for (( ret = 0; ret < "${#IPMI_FRU_EEPROM_FILE[@]}"; ++ret )); do
|
||||
[ -n "${IPMI_FRU_EEPROM_FILE[*]+1}" ] || \
|
||||
[ -n "${IPMI_FRU_EEPROM_BUSADDR[*]+1}" ]|| break
|
||||
done
|
||||
|
||||
if [[ "$name" =~ ^of-name:(.*)$ || "$name" =~ ^([^:]*)$ ]]; then
|
||||
local ofn="${BASH_REMATCH[1]}"
|
||||
local file
|
||||
file="$(of_name_to_eeprom "$ofn")" || return
|
||||
IPMI_FRU_EEPROM_FILE["$ret"]="$file"
|
||||
elif [[ "$name" =~ ^frudev-name:(.*)$ ]]; then
|
||||
local fdn="${BASH_REMATCH[1]}"
|
||||
local start=$SECONDS
|
||||
local file
|
||||
while (( SECONDS - start < 300 )); do
|
||||
local rc=0
|
||||
ipmi_fru_device_alloc "$fdn" "$ret" || rc=$?
|
||||
(( rc == 0 )) && break
|
||||
# Immediately return any errors, 80 is special to signify retry
|
||||
(( rc != 80 )) && return $rc
|
||||
sleep 1
|
||||
done
|
||||
else
|
||||
echo "Invalid IPMI FRU eeprom specification: $name" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ipmi_fru_free() {
|
||||
unset 'IPMI_FRU_EEPROM_FILE[$1]'
|
||||
unset 'IPMI_FRU_EEPROM_BUSADDR[$1]'
|
||||
}
|
||||
|
||||
checksum() {
|
||||
local -n checksum_arr="$1"
|
||||
local checksum=0
|
||||
for byte in "${checksum_arr[@]}"; do
|
||||
checksum=$((checksum + byte))
|
||||
done
|
||||
echo $((checksum & 0xff))
|
||||
}
|
||||
|
||||
fix_checksum() {
|
||||
local -n fix_checksum_arr="$1"
|
||||
old_cksum=${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]}
|
||||
((fix_checksum_arr[IPMI_FRU_CHECKSUM_IDX]-=$(checksum fix_checksum_arr)))
|
||||
((fix_checksum_arr[IPMI_FRU_CHECKSUM_IDX]&=0xff))
|
||||
printf 'Corrected %s checksum from 0x%02X -> 0x%02X\n' \
|
||||
"$1" "${old_cksum}" "${fix_checksum_arr[$IPMI_FRU_CHECKSUM_IDX]}" >&2
|
||||
}
|
||||
|
||||
read_bytes() {
|
||||
# shellcheck disable=SC2206
|
||||
local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-})
|
||||
local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}"
|
||||
local offset="$2"
|
||||
local size="$3"
|
||||
|
||||
if (( "${#busaddr[@]}" > 0)); then
|
||||
echo "Reading ${busaddr[*]} at $offset for $size" >&2
|
||||
# shellcheck disable=SC2046
|
||||
i2ctransfer -f -y "${busaddr[0]}" $("${busaddr[2]}" "${busaddr[1]}" "$offset") "r$size"
|
||||
else
|
||||
echo "Reading $file at $offset for $size" >&2
|
||||
dd if="$file" bs=1 count="$size" skip="$offset" 2>/dev/null | \
|
||||
hexdump -v -e '1/1 "%d "'
|
||||
fi
|
||||
}
|
||||
|
||||
write_bytes() {
|
||||
# shellcheck disable=SC2206
|
||||
local busaddr=(${IPMI_FRU_EEPROM_BUSADDR["$1"]-})
|
||||
local file="${IPMI_FRU_EEPROM_FILE["$1"]-$1}"
|
||||
local offset="$2"
|
||||
local -n bytes_arr="$3"
|
||||
|
||||
if (( "${#busaddr[@]}" > 0)); then
|
||||
echo "Writing ${busaddr[*]} at $offset for ${#bytes_arr[@]}" >&2
|
||||
# shellcheck disable=SC2046
|
||||
i2ctransfer -f -y "${busaddr[0]}" $("${busaddr[2]}" "${busaddr[1]}" "$offset" "${#bytes_arr[@]}") "${bytes_arr[@]}"
|
||||
else
|
||||
local hexstr
|
||||
hexstr="$(printf '\\x%x' "${bytes_arr[@]}")" || return
|
||||
echo "Writing $file at $offset for ${#bytes_arr[@]}" >&2
|
||||
# shellcheck disable=SC2059
|
||||
printf "$hexstr" | dd of="$file" bs=1 seek="$offset" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
read_header() {
|
||||
local eeprom="$1"
|
||||
local -n header_arr="$2"
|
||||
|
||||
# shellcheck disable=SC2207
|
||||
header_arr=($(read_bytes "$eeprom" 0 8)) || return
|
||||
echo "Checking $eeprom FRU Header version" >&2
|
||||
# FRU header is always version 1
|
||||
(( header_arr[0] == 1 )) || return
|
||||
echo "Checking $eeprom FRU Header checksum" >&2
|
||||
local sum
|
||||
sum="$(checksum header_arr)" || return
|
||||
# Checksums should be valid
|
||||
(( sum == 0 )) || return 10
|
||||
}
|
||||
|
||||
read_area() {
|
||||
local eeprom="$1"
|
||||
local offset="$2"
|
||||
local -n area_arr="$3"
|
||||
local area_size="${4-0}"
|
||||
|
||||
offset=$((offset*8))
|
||||
# shellcheck disable=SC2207
|
||||
area_arr=($(read_bytes "$eeprom" "$offset" 8)) || return
|
||||
echo "Checking $eeprom $offset FRU Area version" >&2
|
||||
# FRU Area is always version 1
|
||||
(( area_arr[0] == 1 )) || return
|
||||
if (( area_size == 0 )); then
|
||||
area_size=${area_arr[$IPMI_FRU_AREA_HEADER_SIZE_IDX]}
|
||||
fi
|
||||
# shellcheck disable=SC2207
|
||||
area_arr=($(read_bytes "$eeprom" "$offset" $((area_size*8)))) || return
|
||||
echo "Checking $eeprom $offset FRU Area checksum" >&2
|
||||
local sum
|
||||
sum="$(checksum area_arr)" || return
|
||||
# Checksums should be valid
|
||||
(( sum == 0 )) || return 10
|
||||
}
|
||||
|
||||
ipmi_fru_init=1
|
||||
@@ -0,0 +1,18 @@
|
||||
SUMMARY = "gBMC Health Metrics Blob"
|
||||
DESCRIPTION = "BMC health metrics IPMI blob handler."
|
||||
GOOGLE_MISC_PROJ = "metrics-ipmi-blobs"
|
||||
|
||||
require ../google-misc/google-misc.inc
|
||||
|
||||
inherit pkgconfig
|
||||
|
||||
DEPENDS += " \
|
||||
phosphor-ipmi-blobs \
|
||||
phosphor-logging \
|
||||
protobuf-native \
|
||||
protobuf \
|
||||
"
|
||||
|
||||
FILES:${PN} += "${libdir}/blob-ipmid"
|
||||
|
||||
EXTRA_OEMESON += "-Dtests=disabled"
|
||||
@@ -0,0 +1,16 @@
|
||||
SUMMARY = "Google libcr51sign"
|
||||
DESCRIPTION = "Google libcr51sign"
|
||||
GOOGLE_MISC_PROJ = "libcr51sign"
|
||||
|
||||
require ../google-misc/google-misc.inc
|
||||
|
||||
inherit pkgconfig
|
||||
|
||||
# We need to suppress these warnings in OpenSSL 3.0+ until a fix is available
|
||||
CFLAGS += " \
|
||||
-Wno-deprecated-declarations \
|
||||
"
|
||||
|
||||
DEPENDS += " \
|
||||
openssl \
|
||||
"
|
||||
@@ -0,0 +1,24 @@
|
||||
SUMMARY = "Nanopb library"
|
||||
DESCRIPTION = "Nanopb - Protocol Buffers for Embedded Systems"
|
||||
HOMEPAGE = "https://github.com/nanopb/nanopb"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=9db4b73a55a3994384112efcdb37c01f"
|
||||
|
||||
inherit cmake python3native
|
||||
|
||||
SRC_URI = "git://github.com/nanopb/nanopb;branch=master;protocol=https"
|
||||
SRCREV = "f7e4140a27d9e63517b5d596bc117bd6d5248888"
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
DEPENDS = "protobuf-native python3-protobuf"
|
||||
|
||||
RDEPENDS:${PN}-generator += "python3 python3-protobuf"
|
||||
|
||||
PACKAGES:prepend = "${PN}-generator ${PN}-runtime "
|
||||
|
||||
FILES:${PN}-generator = "${libdir}/python* ${bindir}"
|
||||
|
||||
FILES:${PN}-runtime = "${libdir}/*.so.*"
|
||||
|
||||
BBCLASSEXTEND = "native"
|
||||
@@ -0,0 +1,5 @@
|
||||
[NetDev]
|
||||
Name=gbmcbrncsidhcp
|
||||
Kind=veth
|
||||
[Peer]
|
||||
Name=gbmcncsidhcp
|
||||
@@ -0,0 +1,4 @@
|
||||
[Match]
|
||||
Name=gbmcbrncsidhcp
|
||||
[Network]
|
||||
Bridge=gbmcbr
|
||||
@@ -0,0 +1,5 @@
|
||||
[NetDev]
|
||||
Name=gbmcncsidhcp
|
||||
Kind=veth
|
||||
[Peer]
|
||||
Name=gbmcbrncsidhcp
|
||||
@@ -0,0 +1,10 @@
|
||||
[Match]
|
||||
Name=gbmcncsidhcp
|
||||
[Network]
|
||||
DHCP=false
|
||||
IPv6AcceptRA=false
|
||||
LLMNR=false
|
||||
MulticastDNS=false
|
||||
LinkLocalAddressing=ipv6
|
||||
# TODO: Change address back to fdb5:0481:10ce::1/64
|
||||
Address=fdb5:0481:10ce::2/64
|
||||
@@ -0,0 +1,33 @@
|
||||
# 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.
|
||||
|
||||
[ -n "${gbmc_ncsi_clear_ip-}" ] && return
|
||||
|
||||
source /usr/libexec/ncsid_lib.sh || exit
|
||||
|
||||
gbmc_ncsi_clear_ip_hook() {
|
||||
local ip="${1-}"
|
||||
|
||||
# We only want to clear our IPs if we are assigning a new IP
|
||||
[ -z "$ip" ] && return
|
||||
|
||||
echo "Removing Persistent NCSI IPs" >&2
|
||||
SetStatic xyz.openbmc_project.Network '@NCSI_IF@' 2>/dev/null || true
|
||||
UpdateIP xyz.openbmc_project.Network '@NCSI_IF@' '0.0.0.0' '0' 2>/dev/null || true
|
||||
UpdateIP xyz.openbmc_project.Network '@NCSI_IF@' '::' '0' 2>/dev/null || true
|
||||
}
|
||||
|
||||
GBMC_BR_LIB_SET_IP_HOOKS+=(gbmc_ncsi_clear_ip_hook)
|
||||
|
||||
gbmc_ncsi_clear_ip=1
|
||||
@@ -0,0 +1,45 @@
|
||||
table inet filter {
|
||||
chain ncsi_input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
iifname != @NCSI_IF@ accept
|
||||
ct state established accept
|
||||
ip6 daddr ff00::/8 goto ncsi_brd_input
|
||||
ip6 daddr fe80::/64 goto ncsi_legacy_input
|
||||
}
|
||||
chain ncsi_gbmc_br_pub_input {
|
||||
jump gbmc_br_pub_input
|
||||
jump ncsi_legacy_input
|
||||
reject
|
||||
}
|
||||
chain gbmc_br_pub_input {
|
||||
ip6 nexthdr icmpv6 accept
|
||||
}
|
||||
chain ncsi_legacy_input {
|
||||
jump ncsi_any_input
|
||||
tcp dport 3959 accept
|
||||
udp dport 3959 accept
|
||||
tcp dport 3967 accept
|
||||
udp dport 3967 accept
|
||||
}
|
||||
chain ncsi_brd_input {
|
||||
jump ncsi_any_input
|
||||
}
|
||||
chain ncsi_any_input {
|
||||
icmpv6 type nd-neighbor-advert accept
|
||||
icmpv6 type nd-neighbor-solicit accept
|
||||
icmpv6 type nd-router-advert accept
|
||||
}
|
||||
chain ncsi_forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
iifname != @NCSI_IF@ accept
|
||||
oifname != gbmcbr drop
|
||||
ip6 daddr fdb5:0481:10ce::/64 drop
|
||||
ip6 saddr fdb5:0481:10ce::/64 drop
|
||||
}
|
||||
chain ncsi_dhcp_input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
iifname != ncsigbmc accept
|
||||
ip6 nexthdr icmpv6 accept
|
||||
udp dport 547 accept
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
BindsTo=ncsid@@NCSI_IF@.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/sbin/ip link set @NCSI_IF@ alias ncsi
|
||||
ExecStop=/sbin/ip link set @NCSI_IF@ alias ''
|
||||
|
||||
[Install]
|
||||
WantedBy=nic-hostful@@NCSI_IF@.target
|
||||
WantedBy=nic-hostless@@NCSI_IF@.target
|
||||
@@ -0,0 +1,152 @@
|
||||
# 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.
|
||||
|
||||
[ -n "${gbmc_ncsi_br_deprecated_ips_lib-}" ] && return
|
||||
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_ncsi_br_deprecated_ips_init=
|
||||
gbmc_ncsi_br_deprecated_ips_confip=
|
||||
gbmc_ncsi_br_deprecated_ips_lastip=
|
||||
gbmc_ncsi_br_deprecated_ips_lastncsi=
|
||||
gbmc_ncsi_br_deprecated_ips_confncsi=
|
||||
|
||||
gbmc_ncsi_br_deprecated_ips_update() {
|
||||
[ -n "$gbmc_ncsi_br_deprecated_ips_init" ] || return
|
||||
[ "$gbmc_ncsi_br_deprecated_ips_confip" != "$gbmc_ncsi_br_deprecated_ips_lastip" ] || \
|
||||
[ "$gbmc_ncsi_br_deprecated_ips_confncsi" != "$gbmc_ncsi_br_deprecated_ips_lastncsi" ] || return
|
||||
gbmc_ncsi_br_deprecated_ips_confip="$gbmc_ncsi_br_deprecated_ips_lastip"
|
||||
gbmc_ncsi_br_deprecated_ips_confncsi="$gbmc_ncsi_br_deprecated_ips_lastncsi"
|
||||
|
||||
printf 'gBMC NCSI Deprecated Addrs: %s\n' \
|
||||
"${gbmc_ncsi_br_deprecated_ips_lastip:-(deleted)}" >&2
|
||||
|
||||
local contents=
|
||||
local nfcontents=
|
||||
if [ -n "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then
|
||||
local pfx_bytes=()
|
||||
ip_to_bytes pfx_bytes "$gbmc_ncsi_br_deprecated_ips_lastip"
|
||||
|
||||
local pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
(( pfx_bytes[9] &= 0xf0 ))
|
||||
local stateless_pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
local stateless_ip=
|
||||
if [ -e /sys/class/net/gbmcbr ]; then
|
||||
local gbmcbr_mac="$(ip link show gbmcbr | tail -n 1 | awk '{print $2}')"
|
||||
local gbmcbr_eui48="$(mac_to_eui48 "$gbmcbr_mac")"
|
||||
stateless_ip="$(ip_pfx_concat "$stateless_pfx/80" "$gbmcbr_eui48")"
|
||||
stateless_ip="${stateless_ip%/*}"
|
||||
fi
|
||||
pfx_bytes[8]=0
|
||||
pfx_bytes[9]=0
|
||||
local host_pfx=
|
||||
if [ -n "${gbmc_ncsi_br_deprecated_ips_confncsi}" ]; then
|
||||
# Only impersonate the host if we have an NCSI state machine
|
||||
host_pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
fi
|
||||
read -r -d '' contents <<EOF
|
||||
[Network]
|
||||
IPv6ProxyNDP=yes
|
||||
IPv6ProxyNDPAddress=$pfx
|
||||
IPv6ProxyNDPAddress=$stateless_pfx
|
||||
${host_pfx:+IPv6ProxyNDPAddress=}$host_pfx
|
||||
${stateless_ip:+IPv6ProxyNDPAddress=}$stateless_ip
|
||||
EOF
|
||||
read -r -d '' nfcontents <<EOF
|
||||
table inet filter {
|
||||
chain ncsi_input {
|
||||
ip6 saddr != $pfx/76 ip6 daddr $pfx/76 goto ncsi_gbmc_br_pub_input
|
||||
${host_pfx:+ip6 daddr $host_pfx/64 goto ncsi_legacy_input}
|
||||
}
|
||||
chain ncsi_forward {
|
||||
ip6 saddr != $pfx/76 ip6 daddr $pfx/76 accept
|
||||
}
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
local file
|
||||
for file in /run/systemd/network/{00,}-bmc-@NCSI_IF@.network.d/50-deprecated.conf; do
|
||||
mkdir -p -m 755 "$(dirname "$file")"
|
||||
if [ -z "$contents" ]; then
|
||||
rm -f "$file"
|
||||
else
|
||||
printf '%s' "$contents" >"$file"
|
||||
fi
|
||||
done
|
||||
|
||||
# Ensure that systemd-networkd performs a reconfiguration as it doesn't
|
||||
# currently check the mtime of drop-in files.
|
||||
touch -c /etc/systemd/network/*-bmc-@NCSI_IF@.network
|
||||
|
||||
if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then
|
||||
networkctl reload && networkctl reconfigure @NCSI_IF@
|
||||
fi
|
||||
|
||||
local rfile=/run/nftables/40-gbmc-ncsi-br.rules
|
||||
mkdir -p -m 755 "$(dirname "$rfile")"
|
||||
if [ -z "$nfcontents" ]; then
|
||||
rm -f "$rfile"
|
||||
else
|
||||
printf '%s' "$nfcontents" >"$rfile"
|
||||
fi
|
||||
systemctl reset-failed nftables && systemctl --no-block reload-or-restart nftables || true
|
||||
}
|
||||
|
||||
gbmc_ncsi_br_deprecated_ips_hook() {
|
||||
if [ "$change" = 'init' ]; then
|
||||
gbmc_ncsi_br_deprecated_ips_init=1
|
||||
gbmc_ip_monitor_defer
|
||||
elif [ "$change" = 'defer' ]; then
|
||||
gbmc_ncsi_br_deprecated_ips_update
|
||||
elif [ "$change" = 'addr' -a "$scope" = 'global' -a "$fam" = 'inet6' ] &&
|
||||
[ "$intf" = 'gbmcbr' -o "$intf" = '@NCSI_IF@' ] &&
|
||||
[[ "$flags" != *deprecated* ]]; then
|
||||
local pfx_bytes=()
|
||||
ip_to_bytes pfx_bytes "$ip" || return
|
||||
# No ULA Addresses
|
||||
if (( pfx_bytes[0] & 0xfe == 0xfc )); then
|
||||
return
|
||||
fi
|
||||
# We only want to allow a <pfx>::fd0x address, where x>0
|
||||
if (( pfx_bytes[8] != 0xfd || pfx_bytes[9] & 0xf == 0 )); then
|
||||
return
|
||||
fi
|
||||
for (( i = 10; i < 16; ++i )); do
|
||||
if (( pfx_bytes[i] != 0 )); then
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ "$action" = 'add' -a "$ip" != "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then
|
||||
gbmc_ncsi_br_deprecated_ips_lastip="$ip"
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
if [ "$action" = 'del' -a "$ip" = "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then
|
||||
gbmc_ncsi_br_deprecated_ips_lastip=
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
elif [ "$change" = 'link' -a "$action" = 'add' -a "$intf" = '@NCSI_IF@' ]; then
|
||||
if ip link show '@NCSI_IF@' | grep -q '^ *alias ncsi$'; then
|
||||
gbmc_ncsi_br_deprecated_ips_lastncsi=1
|
||||
gbmc_ip_monitor_defer
|
||||
else
|
||||
gbmc_ncsi_br_deprecated_ips_lastncsi=
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_ncsi_br_deprecated_ips_hook)
|
||||
|
||||
gbmc_ncsi_br_deprecated_ips_lib=1
|
||||
@@ -0,0 +1,87 @@
|
||||
# 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.
|
||||
|
||||
[ -n "${gbmc_ncsi_br_pub_addr_lib-}" ] && return
|
||||
|
||||
[ ! -e /usr/share/gbmc-br-lib.sh ] && return
|
||||
|
||||
source /usr/share/network/lib.sh || exit
|
||||
source /usr/share/gbmc-br-lib.sh || exit
|
||||
|
||||
gbmc_ncsi_br_pub_addr_init=
|
||||
gbmc_ncsi_br_pub_addr_lastip=
|
||||
gbmc_ncsi_br_pub_addr_confip=
|
||||
|
||||
gbmc_ncsi_br_pub_addr_update() {
|
||||
[ -n "$gbmc_ncsi_br_pub_addr_init" ] || return
|
||||
[ "$gbmc_ncsi_br_pub_addr_confip" != "$gbmc_ncsi_br_pub_addr_lastip" ] || return
|
||||
gbmc_ncsi_br_pub_addr_confip="$gbmc_ncsi_br_pub_addr_lastip"
|
||||
|
||||
printf 'gBMC Bridge Pub Addr from NCSI: %s\n' \
|
||||
"${gbmc_ncsi_br_pub_addr_lastip:-(deleted)}" >&2
|
||||
|
||||
local pfx_bytes=()
|
||||
if [ -n "$gbmc_ncsi_br_pub_addr_lastip" ]; then
|
||||
ip_to_bytes pfx_bytes "$gbmc_ncsi_br_pub_addr_lastip"
|
||||
# Ensure we have a /64 or an fdxx address
|
||||
if (( pfx_bytes[8] != 0xfd || pfx_bytes[9] == 0 )); then
|
||||
local i
|
||||
for (( i = 8; i < 16; ++i )); do
|
||||
if (( pfx_bytes[$i] != 0 )); then
|
||||
pfx_bytes=()
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
local contents=
|
||||
if (( ${#pfx_bytes[@]} != 0 )); then
|
||||
pfx_bytes[8]=0xfd
|
||||
# We never want to use the stateless pfx
|
||||
if (( pfx_bytes[9] == 0 )); then
|
||||
pfx_bytes[9]=0x01
|
||||
fi
|
||||
# Remove any existing persisted IP
|
||||
gbmc_br_set_ip
|
||||
# Load the IP to the bridge non-persistently
|
||||
gbmc_br_reload_ip "$(ip_bytes_to_str pfx_bytes)"
|
||||
else
|
||||
gbmc_br_reload_ip
|
||||
fi
|
||||
}
|
||||
|
||||
gbmc_ncsi_br_pub_addr_hook() {
|
||||
if [ "$change" = 'init' ]; then
|
||||
gbmc_ncsi_br_pub_addr_init=1
|
||||
gbmc_ip_monitor_defer
|
||||
elif [ "$change" = 'defer' ]; then
|
||||
gbmc_ncsi_br_pub_addr_update
|
||||
elif [ "$change" = 'addr' -a "$intf" = '@NCSI_IF@' ] &&
|
||||
[ "$scope" = 'global' -a "$fam" = 'inet6' ] &&
|
||||
[[ "$flags" != *deprecated* ]]; then
|
||||
if [ "$action" = 'add' -a "$ip" != "$gbmc_ncsi_br_pub_addr_lastip" ]; then
|
||||
gbmc_ncsi_br_pub_addr_lastip="$ip"
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
if [ "$action" = 'del' -a "$ip" = "$gbmc_ncsi_br_pub_addr_lastip" ]; then
|
||||
gbmc_ncsi_br_pub_addr_lastip=
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_ncsi_br_pub_addr_hook)
|
||||
|
||||
gbmc_ncsi_br_pub_addr_lib=1
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=gBMC DHCP Relay Agent Daemon
|
||||
After=network.target
|
||||
StartLimitIntervalSec=10
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
ExecStart=/usr/sbin/dhcrelay -d --no-pid -rp 3967 -l gbmcncsidhcp -u ff02::1:2%%@NCSI_IF@
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=gBMC NCSI RA Discovery
|
||||
After=network.target
|
||||
StartLimitIntervalSec=10
|
||||
StartLimitBurst=3
|
||||
Conflicts=nic-hostless@@NCSI_IF@.target
|
||||
Conflicts=nic-hostful@@NCSI_IF@.target
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
ExecStart=/usr/libexec/gbmc-ncsi-ip-from-ra.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/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.
|
||||
|
||||
[ ! -e /usr/share/gbmc-br-lib.sh ] && exit
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
# shellcheck source=meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-lib.sh
|
||||
source /usr/share/gbmc-br-lib.sh || exit
|
||||
|
||||
NCSI_IF='@NCSI_IF@'
|
||||
|
||||
old_pfx=
|
||||
old_fqdn=
|
||||
old_rtr=
|
||||
|
||||
set_host() {
|
||||
[[ -n "$host" && -n "$domain" && -n "$hextet" ]] || return
|
||||
|
||||
local fqdn="$host-n$hextet.$domain"
|
||||
[ "$fqdn" != "$old_fqdn" ] || return
|
||||
old_fqdn="$fqdn"
|
||||
|
||||
echo "Found hostname $fqdn" >&2
|
||||
hostnamectl set-hostname "$fqdn" || true
|
||||
}
|
||||
|
||||
set_net() {
|
||||
[[ -n "$pfx" && -n "$rtr" ]] || return
|
||||
[[ "$pfx" != "$old_pfx" || "$rtr" != "$old_rtr" ]] || return
|
||||
old_pfx="$pfx"
|
||||
old_rtr="$rtr"
|
||||
|
||||
echo "Found prefix $pfx from $rtr" >&2
|
||||
|
||||
# We no longer need NCSId if we are in this configuration
|
||||
systemctl stop --no-block ncsid@"$NCSI_IF" || true
|
||||
|
||||
# Save the IP address for the interface
|
||||
gbmc_br_set_ip "$pfx" || true
|
||||
|
||||
# DHCP Relay workaround until alternate source port is supported
|
||||
# TODO: Remove this once internal relaying cleanups land
|
||||
gbmc-ncsi-smartnic-wa.sh || true
|
||||
}
|
||||
|
||||
w=60
|
||||
while true; do
|
||||
start=$SECONDS
|
||||
while read -r line; do
|
||||
if [ -z "$line" ]; then
|
||||
hextet=
|
||||
pfx=
|
||||
host=
|
||||
domain=
|
||||
elif [[ "$line" =~ ^Prefix' '*:' '*(.*)/([0-9]+)$ ]]; then
|
||||
t_pfx="${BASH_REMATCH[1]}"
|
||||
t_pfx_len="${BASH_REMATCH[2]}"
|
||||
ip_to_bytes t_pfx_b "$t_pfx" || continue
|
||||
(( t_pfx_len == 76 && t_pfx_b[8] & 0xfd == 0xfd )) || continue
|
||||
(( t_pfx_b[9] |= 1 ))
|
||||
hextet="fd$(printf '%02x' "${t_pfx_b[9]}")"
|
||||
pfx="$(ip_bytes_to_str t_pfx_b)"
|
||||
elif [[ "$line" =~ ^'DNS search list'' '*:' '*([^.]+)(.*[.]google[.]com)$ ]]; then
|
||||
# Ideally, we use PCRE and with lookahead and can do this in a single regex
|
||||
# ^([a-zA-Z0-9-]+(?=-n[a-fA-F0-9]{1,4})|[a-zA-Z0-9-]+(?!-n[a-fA-F0-9]{1,4}))[^.]*[.]((?:[a-zA-Z0-9]*[.])*google[.]com)$
|
||||
# Instead we do multiple steps to extract the needed info
|
||||
host="${BASH_REMATCH[1]}"
|
||||
domain="${BASH_REMATCH[2]#.}"
|
||||
if [[ "$host" =~ (-n[a-fA-F0-9]{1,4})$ ]]; then
|
||||
host="${host%"${BASH_REMATCH[1]}"}"
|
||||
fi
|
||||
elif [[ "$line" =~ ^from' '(.*)$ ]]; then
|
||||
rtr="${BASH_REMATCH[1]}"
|
||||
set_net || true
|
||||
set_host || true
|
||||
fi
|
||||
done < <(rdisc6 -d -m "$NCSI_IF" -w $(( w * 1000 )) 2>/dev/null)
|
||||
# If rdisc6 exits early we still want to wait the full `w` time before
|
||||
# starting again.
|
||||
(( timeout = start + w - SECONDS ))
|
||||
sleep $(( timeout < 0 ? 0 : timeout ))
|
||||
done
|
||||
@@ -0,0 +1,85 @@
|
||||
# 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.
|
||||
|
||||
[ -n "${gbmc_ncsi_nft_lib-}" ] && return
|
||||
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_ncsi_nft_init=
|
||||
gbmc_ncsi_nft_lastip4=
|
||||
gbmc_ncsi_nft_lastip6=
|
||||
|
||||
gbmc_ncsi_nft_update() {
|
||||
[ -n "$gbmc_ncsi_nft_init" ] || return
|
||||
|
||||
printf 'NCSI firewall for IPv4(%s) IPv6(%s)\n' \
|
||||
"${gbmc_ncsi_nft_lastip4:-(deleted)}" \
|
||||
"${gbmc_ncsi_nft_lastip6:-(deleted)}" >&2
|
||||
|
||||
local contents=
|
||||
contents+='table inet filter {'$'\n'
|
||||
contents+=' chain ncsi_input {'$'\n'
|
||||
|
||||
local ip4="$gbmc_ncsi_nft_lastip4"
|
||||
if [ -n "$ip4" ]; then
|
||||
contents+=" ip daddr $ip4 goto ncsi_legacy_input"$'\n'
|
||||
fi
|
||||
|
||||
local ip6="$gbmc_ncsi_nft_lastip6"
|
||||
if [ -n "$ip6" ]; then
|
||||
contents+=" ip6 daddr $ip6 goto ncsi_legacy_input"$'\n'
|
||||
fi
|
||||
|
||||
contents+=' }'$'\n'
|
||||
contents+='}'$'\n'
|
||||
|
||||
local rfile=/run/nftables/30-gbmc-ncsi-in.rules
|
||||
mkdir -p -m 755 "$(dirname "$rfile")"
|
||||
printf '%s' "$contents" >"$rfile"
|
||||
|
||||
systemctl reset-failed nftables && systemctl --no-block reload-or-restart nftables || true
|
||||
}
|
||||
|
||||
gbmc_ncsi_nft_hook() {
|
||||
if [ "$change" = 'init' ]; then
|
||||
gbmc_ncsi_nft_init=1
|
||||
gbmc_ncsi_nft_update
|
||||
elif [ "$change" = 'addr' -a "$intf" = '@NCSI_IF@' -a "$scope" = 'global' ]; then
|
||||
if [ "$fam" = 'inet6' ]; then
|
||||
local -n lastip='gbmc_ncsi_nft_lastip6'
|
||||
local pfx_bytes=()
|
||||
ip_to_bytes pfx_bytes "$ip" || return
|
||||
# We only want to allow a <pfx>:: address
|
||||
for (( i = 8; i < 16; ++i )); do
|
||||
if (( pfx_bytes[i] != 0 )); then
|
||||
return
|
||||
fi
|
||||
done
|
||||
else
|
||||
local -n lastip='gbmc_ncsi_nft_lastip4'
|
||||
fi
|
||||
if [ "$action" = 'add' -a "$ip" != "$lastip" ]; then
|
||||
lastip="$ip"
|
||||
gbmc_ncsi_nft_update
|
||||
fi
|
||||
if [ "$action" = 'del' -a "$ip" = "$lastip" ]; then
|
||||
lastip=
|
||||
gbmc_ncsi_nft_update
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_ncsi_nft_hook)
|
||||
|
||||
gbmc_ncsi_nft_lib=1
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Set NICEnabled property to true
|
||||
Wants=xyz.openbmc_project.Network.service
|
||||
After=xyz.openbmc_project.Network.service
|
||||
Wants=mapper-wait@-xyz-openbmc_project-network-@NCSI_IF@.service
|
||||
After=mapper-wait@-xyz-openbmc_project-network-@NCSI_IF@.service
|
||||
StartLimitIntervalSec=10
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=busctl set-property xyz.openbmc_project.Network /xyz/openbmc_project/network/@NCSI_IF@ xyz.openbmc_project.Network.EthernetInterface NICEnabled b true
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/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.
|
||||
|
||||
override=/run/systemd/system/gbmc-ncsi-dhcrelay.service.d/10-nosp.conf
|
||||
mkdir -p "$(dirname "$override")"
|
||||
echo '[Service]' >"$override"
|
||||
echo 'ExecStart=' >>"$override"
|
||||
# Remove the source relay port from the relay, bringing it back to run on
|
||||
# the default port 547. Our relays don't support the source port option needed
|
||||
# to run on 3967 for our legacy NICs.
|
||||
grep '^ExecStart=' /lib/systemd/system/gbmc-ncsi-dhcrelay.service | \
|
||||
sed 's, -rp 3967,,' >>"$override"
|
||||
|
||||
override=/run/systemd/system/gbmc-br-dhcp.service.d/10-direct.conf
|
||||
mkdir -p "$(dirname "$override")"
|
||||
echo '[Service]' >"$override"
|
||||
echo 'ExecStart=' >>"$override"
|
||||
# Switch the gbmcbr interface for the NCSI one to avoid passing the SOLICIT
|
||||
# message through the BMC relay.
|
||||
grep '^ExecStart=' /lib/systemd/system/gbmc-br-dhcp.service | \
|
||||
sed 's, -i gbmcbr, -i @NCSI_IF@,' >>"$override"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl reset-failed gbmc-ncsi-dhcrelay
|
||||
systemctl restart --no-block gbmc-ncsi-dhcrelay
|
||||
systemctl reset-failed gbmc-br-dhcp
|
||||
systemctl restart --no-block gbmc-br-dhcp
|
||||
|
||||
read -r -d '' contents <<EOF
|
||||
table inet filter {
|
||||
chain ncsi_legacy_input {
|
||||
udp dport {546,547} accept
|
||||
}
|
||||
}
|
||||
EOF
|
||||
rfile=/run/nftables/60-gbmc-ncsi-ra.rules
|
||||
mkdir -p "$(dirname "$rfile")"
|
||||
printf '%s' "$contents" >"$rfile"
|
||||
systemctl reset-failed nftables
|
||||
systemctl --no-block reload-or-restart nftables
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=SSL/SSH multiplexer
|
||||
Requires=gbmc-ncsi-sslh.socket
|
||||
After=gbmc-ncsi-sslh.socket
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/sbin/sslh -n -f --ssh [::1]:22 --http [::1]:80 --tls [::1]:443
|
||||
KillMode=process
|
||||
#Hardening
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectControlGroups=true
|
||||
MountFlags=private
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
MemoryDenyWriteExecute=true
|
||||
DynamicUser=true
|
||||
@@ -0,0 +1,6 @@
|
||||
[Socket]
|
||||
BindToDevice=@NCSI_IF@
|
||||
ListenStream=3967
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
@@ -0,0 +1,149 @@
|
||||
SUMMARY = "Configures ncsi for a gBMC system"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
SRC_URI += " \
|
||||
file://-bmc-gbmcbrncsidhcp.netdev \
|
||||
file://-bmc-gbmcbrncsidhcp.network \
|
||||
file://-bmc-gbmcncsidhcp.netdev \
|
||||
file://-bmc-gbmcncsidhcp.network \
|
||||
file://50-gbmc-ncsi.rules.in \
|
||||
file://gbmc-ncsi-dhcrelay.service.in \
|
||||
file://gbmc-ncsi-ip-from-ra.service.in \
|
||||
file://gbmc-ncsi-ip-from-ra.sh.in \
|
||||
file://gbmc-ncsi-smartnic-wa.sh.in \
|
||||
file://gbmc-ncsi-sslh.socket.in \
|
||||
file://gbmc-ncsi-sslh.service \
|
||||
file://gbmc-ncsi-nft.sh.in \
|
||||
file://gbmc-ncsi-br-pub-addr.sh.in \
|
||||
file://gbmc-ncsi-br-deprecated-ips.sh.in \
|
||||
file://gbmc-ncsi-set-nicenabled.service.in \
|
||||
file://gbmc-ncsi-alias.service.in \
|
||||
file://50-gbmc-ncsi-clear-ip.sh.in \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
RDEPENDS:${PN} += " \
|
||||
bash \
|
||||
dhcp-relay \
|
||||
gbmc-ip-monitor \
|
||||
ncsid \
|
||||
network-sh \
|
||||
nftables-systemd \
|
||||
sslh \
|
||||
ndisc6-rdisc6 \
|
||||
"
|
||||
|
||||
FILES:${PN} += " \
|
||||
${datadir}/gbmc-br-lib \
|
||||
${datadir}/gbmc-ip-monitor \
|
||||
${systemd_unitdir} \
|
||||
"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += " \
|
||||
gbmc-ncsi-dhcrelay.service \
|
||||
gbmc-ncsi-sslh.service \
|
||||
gbmc-ncsi-sslh.socket \
|
||||
gbmc-ncsi-set-nicenabled.service \
|
||||
gbmc-ncsi-ip-from-ra.service \
|
||||
"
|
||||
|
||||
do_install:append() {
|
||||
if_name='${GBMC_NCSI_IF_NAME}'
|
||||
if [ -z "$if_name" ]; then
|
||||
echo "Missing if_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -d -m0755 ${D}${sysconfdir}/sysctl.d
|
||||
echo "net.ipv6.conf.$if_name.accept_dad=0" \
|
||||
>>${D}${sysconfdir}/sysctl.d/25-gbmc-ncsi.conf
|
||||
echo "net.ipv6.conf.$if_name.dad_transmits=0" \
|
||||
>>${D}${sysconfdir}/sysctl.d/25-gbmc-ncsi.conf
|
||||
|
||||
install -d -m0755 ${D}${systemd_unitdir}/network
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbrncsidhcp.netdev \
|
||||
${D}${systemd_unitdir}/network/
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbrncsidhcp.network \
|
||||
${D}${systemd_unitdir}/network/
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcncsidhcp.netdev \
|
||||
${D}${systemd_unitdir}/network/
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcncsidhcp.network \
|
||||
${D}${systemd_unitdir}/network/
|
||||
|
||||
netdir=${D}${systemd_unitdir}/network/00-bmc-$if_name.network.d
|
||||
install -d -m0755 "$netdir"
|
||||
echo '[Network]' >>"$netdir"/gbmc-ncsi.conf
|
||||
echo 'DHCP=false' >>"$netdir"/gbmc-ncsi.conf
|
||||
echo 'IPv6AcceptRA=false' >>"$netdir"/gbmc-ncsi.conf
|
||||
echo 'LLMNR=false' >>"$netdir"/gbmc-ncsi.conf
|
||||
echo 'MulticastDNS=false' >>"$netdir"/gbmc-ncsi.conf
|
||||
echo 'LinkLocalAddressing=ipv6' >>"$netdir"/gbmc-ncsi.conf
|
||||
|
||||
nftdir=${D}${sysconfdir}/nftables
|
||||
install -d -m0755 "$nftdir"
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/50-gbmc-ncsi.rules.in \
|
||||
>"$nftdir"/50-gbmc-ncsi.rules
|
||||
|
||||
wantdir=${D}${systemd_system_unitdir}/multi-user.target.wants
|
||||
install -d -m0755 "$wantdir"
|
||||
ln -sv ../ncsid@.service "$wantdir"/ncsid@$if_name.service
|
||||
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-alias.service.in \
|
||||
>${D}${systemd_system_unitdir}/gbmc-ncsi-alias.service
|
||||
install -d -m0755 "${D}${systemd_system_unitdir}/nic-hostless@$if_name.target.wants"
|
||||
ln -sv ../gbmc-ncsi-alias.service "${D}${systemd_system_unitdir}/nic-hostless@$if_name.target.wants"/
|
||||
install -d -m0755 "${D}${systemd_system_unitdir}/nic-hostful@$if_name.target.wants"
|
||||
ln -sv ../gbmc-ncsi-alias.service "${D}${systemd_system_unitdir}/nic-hostful@$if_name.target.wants"/
|
||||
|
||||
install -m 0644 ${WORKDIR}/gbmc-ncsi-sslh.service ${D}${systemd_system_unitdir}
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-sslh.socket.in \
|
||||
>${D}${systemd_system_unitdir}/gbmc-ncsi-sslh.socket
|
||||
|
||||
mondir=${D}${datadir}/gbmc-ip-monitor/
|
||||
install -d -m0755 $mondir
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-nft.sh.in \
|
||||
>${WORKDIR}/gbmc-ncsi-nft.sh
|
||||
install -m644 ${WORKDIR}/gbmc-ncsi-nft.sh $mondir
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-br-pub-addr.sh.in \
|
||||
>${WORKDIR}/gbmc-ncsi-br-pub-addr.sh
|
||||
install -m644 ${WORKDIR}/gbmc-ncsi-br-pub-addr.sh $mondir
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-br-deprecated-ips.sh.in \
|
||||
>${WORKDIR}/gbmc-ncsi-br-deprecated-ips.sh
|
||||
install -m644 ${WORKDIR}/gbmc-ncsi-br-deprecated-ips.sh $mondir
|
||||
|
||||
brlibdir=${D}${datadir}/gbmc-br-lib/
|
||||
install -d -m0755 $brlibdir
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/50-gbmc-ncsi-clear-ip.sh.in \
|
||||
>${WORKDIR}/50-gbmc-ncsi-clear-ip.sh
|
||||
install -m644 ${WORKDIR}/50-gbmc-ncsi-clear-ip.sh $brlibdir
|
||||
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-set-nicenabled.service.in \
|
||||
>${D}${systemd_system_unitdir}/gbmc-ncsi-set-nicenabled.service
|
||||
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-dhcrelay.service.in \
|
||||
>${D}${systemd_system_unitdir}/gbmc-ncsi-dhcrelay.service
|
||||
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-ip-from-ra.service.in \
|
||||
>${WORKDIR}/gbmc-ncsi-ip-from-ra.service
|
||||
install -m0644 ${WORKDIR}/gbmc-ncsi-ip-from-ra.service ${D}${systemd_system_unitdir}
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-ip-from-ra.sh.in \
|
||||
>${WORKDIR}/gbmc-ncsi-ip-from-ra.sh
|
||||
install -d -m0755 ${D}${libexecdir}
|
||||
install -m0755 ${WORKDIR}/gbmc-ncsi-ip-from-ra.sh ${D}${libexecdir}/
|
||||
|
||||
sed "s,@NCSI_IF@,$if_name,g" ${WORKDIR}/gbmc-ncsi-smartnic-wa.sh.in \
|
||||
>${WORKDIR}/gbmc-ncsi-smartnic-wa.sh
|
||||
install -d -m0755 ${D}${bindir}
|
||||
install -m0755 ${WORKDIR}/gbmc-ncsi-smartnic-wa.sh ${D}${bindir}/
|
||||
}
|
||||
|
||||
do_rm_work:prepend() {
|
||||
# HACK: Work around broken do_rm_work not properly calling rm with `--`
|
||||
# It doesn't like filenames that start with `-`
|
||||
rm -rf -- ${WORKDIR}/-*
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
SUMMARY = "Google NCSI daemon"
|
||||
DESCRIPTION = "Google NCSI daemon."
|
||||
GOOGLE_MISC_PROJ = "ncsid"
|
||||
|
||||
require ../google-misc/google-misc.inc
|
||||
|
||||
inherit systemd
|
||||
|
||||
EXTRA_OEMESON = " \
|
||||
-Dtests=disabled \
|
||||
"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += " \
|
||||
dhcp4@.service \
|
||||
dhcp6@.service \
|
||||
ncsid@.service \
|
||||
nic-hostful@.target \
|
||||
nic-hostless@.target \
|
||||
update-ra-gw@.service \
|
||||
update-ra-neighbor@.service \
|
||||
update-ra-neighbor@.timer \
|
||||
update-static-neighbors@.service \
|
||||
update-static-neighbors@.timer \
|
||||
"
|
||||
|
||||
DEPENDS += " \
|
||||
fmt \
|
||||
sdbusplus \
|
||||
stdplus \
|
||||
"
|
||||
|
||||
RDEPENDS:${PN} += " \
|
||||
bash \
|
||||
busybox \
|
||||
iputils-arping \
|
||||
jq \
|
||||
ndisc6-ndisc6 \
|
||||
ndisc6-rdisc6 \
|
||||
systemd \
|
||||
"
|
||||
@@ -0,0 +1,5 @@
|
||||
table inet filter {
|
||||
chain gbmc_br_pub_input {
|
||||
tcp dport 23 accept
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
SUMMARY = "Google DHCP completion daemon"
|
||||
DESCRIPTION = "Google DHCP completion daemon"
|
||||
GOOGLE_MISC_PROJ = "dhcp-done"
|
||||
|
||||
require ../google-misc/google-misc.inc
|
||||
|
||||
inherit systemd
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += "dhcp-done@.service"
|
||||
|
||||
DEPENDS += " \
|
||||
sdeventplus \
|
||||
stdplus \
|
||||
"
|
||||
|
||||
SRC_URI += "file://50-dhcp-done.rules"
|
||||
FILES:${PN} += "${sysconfdir}/nftables"
|
||||
do_install:append() {
|
||||
nftables_dir=${D}${sysconfdir}/nftables
|
||||
install -d -m0755 "$nftables_dir"
|
||||
install -m0644 ${WORKDIR}/50-dhcp-done.rules $nftables_dir/
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC2317
|
||||
# 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.
|
||||
|
||||
cd "$(dirname "$0")" || exit
|
||||
if [ -e ../gbmc-ip-monitor.bb ]; then
|
||||
# shellcheck source=meta-google/recipes-google/test/test-sh/lib.sh
|
||||
source '../../test/test-sh/lib.sh'
|
||||
else
|
||||
# shellcheck source=meta-google/recipes-google/test/test-sh/lib.sh
|
||||
source "$SYSROOT/usr/share/test/lib.sh"
|
||||
fi
|
||||
# shellcheck source=meta-google/recipes-google/networking/files/gbmc-ip-monitor.sh
|
||||
source gbmc-ip-monitor.sh
|
||||
|
||||
test_init_empty() {
|
||||
ip() {
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" '[INIT]'
|
||||
}
|
||||
|
||||
test_init_link_populated() {
|
||||
ip() {
|
||||
if [ "$1" = 'link' ]; then
|
||||
cat <<EOF
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[LINK]1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
[LINK]2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
test_init_addr_populated() {
|
||||
ip() {
|
||||
if [ "$1" = 'addr' ]; then
|
||||
cat <<EOF
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 ::1/128 scope host
|
||||
valid_lft forever preferred_lft forever
|
||||
2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
||||
link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff
|
||||
altname enp0s31f6
|
||||
inet 192.168.242.57/23 brd 192.168.243.255 scope global dynamic noprefixroute eno2
|
||||
valid_lft 83967sec preferred_lft 83967sec
|
||||
inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/64 scope global temporary dynamic
|
||||
valid_lft 518788sec preferred_lft 183sec
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[ADDR]1: lo inet 127.0.0.1/8 scope host lo
|
||||
[ADDR]1: lo inet6 ::1/128 scope host
|
||||
[ADDR]2: eno2 inet 192.168.242.57/23 brd 192.168.243.255 scope global dynamic noprefixroute eno2
|
||||
[ADDR]2: eno2 inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/64 scope global temporary dynamic
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
test_init_route_populated() {
|
||||
ip() {
|
||||
if [[ "$1" == "-4" && "${2-}" == 'route' ]]; then
|
||||
cat <<EOF
|
||||
default via 192.168.243.254 dev eno2 proto dhcp metric 100
|
||||
192.168.242.0/23 dev eno2 proto kernel scope link src 192.168.242.57 metric 100
|
||||
EOF
|
||||
elif [[ "$1" == "-6" && "${2-}" == 'route' ]]; then
|
||||
cat <<EOF
|
||||
::1 dev lo proto kernel metric 256 pref medium
|
||||
fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium
|
||||
fe80::/64 dev eno2 proto kernel metric 100 pref medium
|
||||
EOF
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
str="$(gbmc_ip_monitor_generate_init)" || fail
|
||||
expect_streq "$str" <<EOF
|
||||
[ROUTE]default via 192.168.243.254 dev eno2 proto dhcp metric 100
|
||||
[ROUTE]192.168.242.0/23 dev eno2 proto kernel scope link src 192.168.242.57 metric 100
|
||||
[ROUTE]::1 dev lo proto kernel metric 256 pref medium
|
||||
[ROUTE]fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium
|
||||
[ROUTE]fe80::/64 dev eno2 proto kernel metric 100 pref medium
|
||||
[INIT]
|
||||
EOF
|
||||
}
|
||||
|
||||
testParseNonTag() {
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ''
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' '
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' Data'
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' [LINK]'
|
||||
expect_err 2 gbmc_ip_monitor_parse_line ' [ROUTE]'
|
||||
}
|
||||
|
||||
testParseInit() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[INIT]'
|
||||
expect_streq "$change" 'init'
|
||||
}
|
||||
|
||||
testParseAddrAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[ADDR]2: eno2 inet6 fd01:ff2:5687:4:cf03:45f3:983a:96eb/128 metric 1024 scope global temporary dynamic'
|
||||
expect_streq "$change" 'addr'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$fam" 'inet6'
|
||||
expect_streq "$ip" 'fd01:ff2:5687:4:cf03:45f3:983a:96eb'
|
||||
expect_streq "$scope" 'global'
|
||||
expect_streq "$flags" 'temporary dynamic'
|
||||
}
|
||||
|
||||
testParseAddrDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line '[ADDR]Deleted 2: eno2 inet6 fe80::aaaa:aaff:feaa:aaaa/64 scope link'
|
||||
expect_streq "$change" 'addr'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$fam" 'inet6'
|
||||
expect_streq "$ip" 'fe80::aaaa:aaff:feaa:aaaa'
|
||||
expect_streq "$scope" 'link'
|
||||
expect_streq "$flags" ''
|
||||
}
|
||||
|
||||
testParseRouteAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[ROUTE]fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium"
|
||||
expect_streq "$change" 'route'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$route" 'fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium'
|
||||
}
|
||||
|
||||
testParseRouteDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[ROUTE]Deleted fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium"
|
||||
expect_streq "$change" 'route'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$route" 'fd01:ff2:5687:4::/64 dev eno2 proto ra metric 100 pref medium'
|
||||
}
|
||||
|
||||
testParseLinkAdd() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[LINK]2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000" \
|
||||
< <(echo 'link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff')
|
||||
expect_streq "$change" 'link'
|
||||
expect_streq "$action" 'add'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$mac" 'aa:aa:aa:aa:aa:aa'
|
||||
}
|
||||
|
||||
testParseLinkDel() {
|
||||
expect_err 0 gbmc_ip_monitor_parse_line "[LINK]Deleted 2: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000" \
|
||||
< <(echo 'link/ether aa:aa:aa:aa:aa:aa brd ff:ff:ff:ff:ff:ff')
|
||||
expect_streq "$change" 'link'
|
||||
expect_streq "$action" 'del'
|
||||
expect_streq "$intf" 'eno2'
|
||||
expect_streq "$mac" 'aa:aa:aa:aa:aa:aa'
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Before=systemd-networkd.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=/usr/libexec/gbmc-ip-monitor.sh
|
||||
TimeoutStartSec=5min
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,145 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC2034
|
||||
# shellcheck disable=SC2317
|
||||
# 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.
|
||||
|
||||
# A list of functions which get executed for each netlink event received.
|
||||
# These are configured by the files included below.
|
||||
GBMC_IP_MONITOR_HOOKS=()
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# hooks that are executed after each event.
|
||||
shopt -s nullglob
|
||||
for conf in /usr/share/gbmc-ip-monitor/*.sh; do
|
||||
# shellcheck source=/dev/null
|
||||
source "$conf"
|
||||
done
|
||||
|
||||
gbmc_ip_monitor_run_hooks() {
|
||||
local hook
|
||||
for hook in "${GBMC_IP_MONITOR_HOOKS[@]}"; do
|
||||
"$hook" || continue
|
||||
done
|
||||
}
|
||||
|
||||
gbmc_ip_monitor_generate_init() {
|
||||
ip link | sed 's,^[^ ],[LINK]\0,'
|
||||
local intf=
|
||||
local line
|
||||
while read -r line; do
|
||||
[[ "$line" =~ ^([0-9]+:[[:space:]][^:]+) ]] && intf="${BASH_REMATCH[1]}"
|
||||
[[ "$line" =~ ^[[:space:]]*inet ]] && echo "[ADDR]$intf $line"
|
||||
done < <(ip addr)
|
||||
ip -4 route | sed 's,^,[ROUTE],'
|
||||
ip -6 route | sed 's,^,[ROUTE],'
|
||||
echo '[INIT]'
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=
|
||||
gbmc_ip_monitor_defer_() {
|
||||
sleep 1
|
||||
printf '[DEFER]\n' >&"$GBMC_IP_MONITOR_DEFER"
|
||||
}
|
||||
gbmc_ip_monitor_defer() {
|
||||
[ -z "$GBMC_IP_MONITOR_DEFER_OUTSTANDING" ] || return 0
|
||||
gbmc_ip_monitor_defer_ &
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=1
|
||||
}
|
||||
|
||||
gbmc_ip_monitor_parse_line() {
|
||||
local line="$1"
|
||||
if [[ "$line" == '[INIT]'* ]]; then
|
||||
change=init
|
||||
echo "Initialized" >&2
|
||||
elif [[ "$line" == '[ADDR]'* ]]; then
|
||||
change=addr
|
||||
action=add
|
||||
pfx_re='^\[ADDR\](Deleted )?[0-9]+:[[:space:]]*'
|
||||
intf_re='([^ ]+)[[:space:]]+'
|
||||
fam_re='([^ ]+)[[:space:]]+'
|
||||
addr_re='([^/]+)/[0-9]+[[:space:]]+'
|
||||
metric_re='(metric[[:space:]]+[^ ]+[[:space:]]+)?'
|
||||
brd_re='(brd[[:space:]]+[^ ]+[[:space:]]+)?'
|
||||
scope_re='scope[[:space:]]+([^ ]+)[[:space:]]*(.*)'
|
||||
combined_re="${pfx_re}${intf_re}${fam_re}${addr_re}${metric_re}${brd_re}${scope_re}"
|
||||
if ! [[ "$line" =~ ${combined_re} ]]; then
|
||||
echo "Failed to parse addr: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
intf="${BASH_REMATCH[2]}"
|
||||
fam="${BASH_REMATCH[3]}"
|
||||
ip="${BASH_REMATCH[4]}"
|
||||
scope="${BASH_REMATCH[7]}"
|
||||
flags="${BASH_REMATCH[8]}"
|
||||
elif [[ "$line" == '[ROUTE]'* ]]; then
|
||||
line="${line#[ROUTE]}"
|
||||
change=route
|
||||
action=add
|
||||
if ! [[ "$line" =~ ^\[ROUTE\](Deleted )?(.*)$ ]]; then
|
||||
echo "Failed to parse link: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
route="${BASH_REMATCH[2]}"
|
||||
elif [[ "$line" == '[LINK]'* ]]; then
|
||||
change='link'
|
||||
action=add
|
||||
pfx_re='^\[LINK\](Deleted )?[0-9]+:[[:space:]]*'
|
||||
intf_re='([^:]+):[[:space:]]+'
|
||||
if ! [[ "$line" =~ ${pfx_re}${intf_re} ]]; then
|
||||
echo "Failed to parse link: $line" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ -n "${BASH_REMATCH[1]}" ]; then
|
||||
action=del
|
||||
fi
|
||||
intf="${BASH_REMATCH[2]}"
|
||||
read -ra data || return
|
||||
mac="${data[1]}"
|
||||
elif [[ "$line" == '[DEFER]'* ]]; then
|
||||
GBMC_IP_MONITOR_DEFER_OUTSTANDING=
|
||||
change=defer
|
||||
else
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
return 0 2>/dev/null
|
||||
|
||||
cleanup() {
|
||||
local st="$?"
|
||||
trap - HUP INT QUIT ABRT TERM EXIT
|
||||
jobs -l -p | xargs -r kill || true
|
||||
exit "$st"
|
||||
}
|
||||
trap cleanup HUP INT QUIT ABRT TERM EXIT
|
||||
|
||||
FIFODIR="$(mktemp -d)"
|
||||
mkfifo "$FIFODIR"/fifo
|
||||
exec {GBMC_IP_MONITOR_DEFER}<>"$FIFODIR"/fifo
|
||||
rm -rf "$FIFODIR"
|
||||
|
||||
while read -r line; do
|
||||
gbmc_ip_monitor_parse_line "$line" || continue
|
||||
gbmc_ip_monitor_run_hooks || continue
|
||||
if [ "$change" = 'init' ]; then
|
||||
systemd-notify --ready
|
||||
fi
|
||||
done < <(gbmc_ip_monitor_generate_init; ip monitor link addr route label & cat <&"$GBMC_IP_MONITOR_DEFER")
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Before=systemd-networkd.service
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
Type=oneshot
|
||||
ExecStart=/usr/libexec/gbmc-mac-config.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/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
|
||||
for (( i=0; i<num; i++ )); do
|
||||
if (( mac[5] > 0xff )); then
|
||||
echo "MAC assignment too large: ${mac[*]}" >&2
|
||||
rc=2
|
||||
break
|
||||
fi
|
||||
for intf in ${num_to_intfs[$i]}; do
|
||||
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
|
||||
(( ++mac[5] ))
|
||||
done
|
||||
|
||||
exit $rc
|
||||
@@ -0,0 +1,21 @@
|
||||
[Unit]
|
||||
Description=IPERF3 Server
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/iperf3 -s
|
||||
#Hardening
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectControlGroups=true
|
||||
MountFlags=private
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
MemoryDenyWriteExecute=true
|
||||
DynamicUser=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,155 @@
|
||||
SUMMARY = "Configures the gbmc bridge and filter rules"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
|
||||
SRC_URI += " \
|
||||
file://-bmc-gbmcbr.netdev \
|
||||
file://-bmc-gbmcbr.network.in \
|
||||
file://-bmc-gbmcbrdummy.netdev \
|
||||
file://-bmc-gbmcbrdummy.network \
|
||||
file://+-bmc-gbmcbrusb.network \
|
||||
file://ipmi.service.in \
|
||||
file://50-gbmc-br.rules \
|
||||
file://gbmc-br-ula.sh \
|
||||
file://gbmc-br-from-ra.sh \
|
||||
file://gbmc-br-ensure-ra.sh \
|
||||
file://gbmc-br-ensure-ra.service \
|
||||
file://gbmc-br-gw-src.sh \
|
||||
file://gbmc-br-nft.sh \
|
||||
file://gbmc-br-dhcp.sh \
|
||||
file://50-gbmc-psu-hardreset.sh \
|
||||
file://gbmc-br-dhcp.service \
|
||||
file://gbmc-br-dhcp-term.sh \
|
||||
file://gbmc-br-dhcp-term.service \
|
||||
file://gbmc-br-lib.sh \
|
||||
file://gbmc-br-load-ip.service \
|
||||
file://gbmc-start-dhcp.sh \
|
||||
file://50-gbmc-br-cn-redirect.rules \
|
||||
"
|
||||
|
||||
FILES:${PN}:append = " \
|
||||
${datadir}/gbmc-ip-monitor \
|
||||
${datadir}/gbmc-br-dhcp \
|
||||
${datadir}/gbmc-br-lib.sh \
|
||||
${systemd_unitdir}/network \
|
||||
${sysconfdir}/nftables \
|
||||
${sysconfdir}/avahi/services \
|
||||
"
|
||||
|
||||
RDEPENDS:${PN}:append = " \
|
||||
bash \
|
||||
dhcp-done \
|
||||
gbmc-ip-monitor \
|
||||
mstpd-mstpd \
|
||||
network-sh \
|
||||
ndisc6-rdisc6 \
|
||||
nftables-systemd \
|
||||
"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += " \
|
||||
gbmc-br-ensure-ra.service \
|
||||
gbmc-br-dhcp.service \
|
||||
gbmc-br-dhcp-term.service \
|
||||
gbmc-br-load-ip.service \
|
||||
"
|
||||
|
||||
GBMC_BR_MAC_ADDR ?= ""
|
||||
|
||||
# Generated via https://cd34.com/rfc4193/ based on a MAC from a machine I own
|
||||
# and we allocated it downstream. Intended to only be used within a complete
|
||||
# system of multiple network endpoints.
|
||||
GBMC_ULA_PREFIX = "fdb5:0481:10ce:0"
|
||||
|
||||
def mac_to_eui64(mac):
|
||||
if not mac:
|
||||
return ''
|
||||
b = [int(c, 16) for c in mac.split(':')]
|
||||
b[0] ^= 2
|
||||
b.insert(3, 0xfe)
|
||||
b.insert(3, 0xff)
|
||||
idx = range(0, len(b)-1, 2)
|
||||
return ':'.join([format((b[i] << 8) + b[i+1], '04x') for i in idx])
|
||||
|
||||
GBMC_BRIDGE_INTFS ?= ""
|
||||
|
||||
ethernet_bridge_install() {
|
||||
# install udev rules if any
|
||||
if [ -z "${GBMC_BRIDGE_INTFS}"]; then
|
||||
return
|
||||
fi
|
||||
cat /dev/null > ${WORKDIR}/-ether-bridge.network
|
||||
echo "[Match]" >> ${WORKDIR}/-ether-bridge.network
|
||||
echo "Name=${GBMC_BRIDGE_INTFS}" >> ${WORKDIR}/-ether-bridge.network
|
||||
echo "[Network]" >> ${WORKDIR}/-ether-bridge.network
|
||||
echo "Bridge=gbmcbr" >> ${WORKDIR}/-ether-bridge.network
|
||||
|
||||
install -d ${D}/${sysconfdir}/systemd/network
|
||||
install -m 0644 ${WORKDIR}/-ether-bridge.network ${D}/${sysconfdir}/systemd/network/
|
||||
}
|
||||
|
||||
do_install() {
|
||||
netdir=${D}${systemd_unitdir}/network
|
||||
install -d -m0755 $netdir
|
||||
|
||||
if [ ! -z "${GBMC_BR_MAC_ADDR}" ]; then
|
||||
sfx='${@mac_to_eui64(GBMC_BR_MAC_ADDR)}'
|
||||
addr="Address=${GBMC_ULA_PREFIX}:$sfx/64\nAddress=fe80::$sfx/64"
|
||||
sed -i "s,@ADDR@,$addr," ${WORKDIR}/-bmc-gbmcbr.network.in
|
||||
else
|
||||
sed -i '/@ADDR@/d' ${WORKDIR}/-bmc-gbmcbr.network.in
|
||||
fi
|
||||
|
||||
ethernet_bridge_install
|
||||
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbr.netdev $netdir/
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbr.network.in $netdir/-bmc-gbmcbr.network
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbrdummy.netdev $netdir/
|
||||
install -m0644 ${WORKDIR}/-bmc-gbmcbrdummy.network $netdir/
|
||||
install -m0644 ${WORKDIR}/+-bmc-gbmcbrusb.network $netdir/
|
||||
|
||||
nftables_dir=${D}${sysconfdir}/nftables
|
||||
install -d -m0755 "$nftables_dir"
|
||||
install -m0644 ${WORKDIR}/50-gbmc-br.rules $nftables_dir/
|
||||
install -m0644 ${WORKDIR}/50-gbmc-br-cn-redirect.rules $nftables_dir/
|
||||
|
||||
avahi_dir=${D}${sysconfdir}/avahi/services
|
||||
install -d -m 0755 "$avahi_dir"
|
||||
sed -i 's,@MACHINE@,${MACHINE},g' ${WORKDIR}/ipmi.service.in
|
||||
sed -i 's,@EXTRA_ATTRS@,,g' ${WORKDIR}/ipmi.service.in
|
||||
sed 's,@NAME@,bmc,g' ${WORKDIR}/ipmi.service.in >${avahi_dir}/bmc.ipmi.service
|
||||
sed 's,@NAME@,${MACHINE}-bmc,g' ${WORKDIR}/ipmi.service.in >${avahi_dir}/${MACHINE}-bmc.ipmi.service
|
||||
|
||||
mondir=${D}${datadir}/gbmc-ip-monitor
|
||||
install -d -m0755 "$mondir"
|
||||
install -m0644 ${WORKDIR}/gbmc-br-ula.sh "$mondir"/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-from-ra.sh "$mondir"/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-gw-src.sh "$mondir"/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-nft.sh "$mondir"/
|
||||
|
||||
install -d -m0755 ${D}${libexecdir}
|
||||
install -m0755 ${WORKDIR}/gbmc-br-ensure-ra.sh ${D}${libexecdir}/
|
||||
install -m0755 ${WORKDIR}/gbmc-br-dhcp.sh ${D}${libexecdir}/
|
||||
install -m0755 ${WORKDIR}/gbmc-br-dhcp-term.sh ${D}${libexecdir}/
|
||||
install -d -m0755 ${D}${systemd_system_unitdir}
|
||||
install -m0644 ${WORKDIR}/gbmc-br-ensure-ra.service ${D}${systemd_system_unitdir}/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-dhcp.service ${D}${systemd_system_unitdir}/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-dhcp-term.service ${D}${systemd_system_unitdir}/
|
||||
install -m0644 ${WORKDIR}/gbmc-br-load-ip.service ${D}${systemd_system_unitdir}/
|
||||
install -d -m0755 ${D}${datadir}/gbmc-br-dhcp
|
||||
install -m0644 ${WORKDIR}/50-gbmc-psu-hardreset.sh ${D}${datadir}/gbmc-br-dhcp/
|
||||
|
||||
install -m0644 ${WORKDIR}/gbmc-br-lib.sh ${D}${datadir}/
|
||||
|
||||
install -d ${D}/${bindir}
|
||||
install -m0755 ${WORKDIR}/gbmc-start-dhcp.sh ${D}${bindir}/
|
||||
}
|
||||
|
||||
do_rm_work:prepend() {
|
||||
# HACK: Work around broken do_rm_work not properly calling rm with `--`
|
||||
# It doesn't like filenames that start with `-`
|
||||
rm -rf -- ${WORKDIR}/-*
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[Match]
|
||||
Property=ID_BUS=usb ID_VENDOR_ID=18d1 ID_MODEL_ID=022b
|
||||
[Network]
|
||||
Bridge=gbmcbr
|
||||
[Bridge]
|
||||
# USB speeds tend to be better than 100mbit (100 cost) but worse
|
||||
# than 1gbit (10 cost). Generally around 200mbit.
|
||||
Cost=85
|
||||
@@ -0,0 +1,5 @@
|
||||
[NetDev]
|
||||
Name=gbmcbr
|
||||
Kind=bridge
|
||||
[Bridge]
|
||||
STP=true
|
||||
@@ -0,0 +1,15 @@
|
||||
[Match]
|
||||
Name=gbmcbr
|
||||
[Network]
|
||||
@ADDR@
|
||||
DHCP=false
|
||||
IPv6AcceptRA=true
|
||||
LLMNR=true
|
||||
MulticastDNS=true
|
||||
LinkLocalAddressing=ipv6
|
||||
IPv6PrefixDelegation=yes
|
||||
[IPv6AcceptRA]
|
||||
DHCPv6Client=false
|
||||
RouteMetric=1056
|
||||
[IPv6PrefixDelegation]
|
||||
RouterLifetimeSec=0
|
||||
@@ -0,0 +1,3 @@
|
||||
[NetDev]
|
||||
Name=gbmcbrdummy
|
||||
Kind=dummy
|
||||
@@ -0,0 +1,4 @@
|
||||
[Match]
|
||||
Name=gbmcbrdummy
|
||||
[Network]
|
||||
Bridge=gbmcbr
|
||||
@@ -0,0 +1,24 @@
|
||||
table bridge filter {
|
||||
chain gbmcbr_mark {
|
||||
type filter hook prerouting priority -300;
|
||||
iifname == "cn0" mark set 1 return
|
||||
iifname == "cn1" mark set 2 return
|
||||
}
|
||||
}
|
||||
|
||||
table inet raw {
|
||||
chain gbmcbr_nat_input {
|
||||
type filter hook prerouting priority -300;
|
||||
# client should only use 10166 for this purpose and
|
||||
# it should NOT use service port directly
|
||||
# otherwise drop later if the packets goes into input
|
||||
tcp dport 10167-10168 mark set 0xff
|
||||
mark 1 tcp dport 10166 tcp dport set 10167 notrack
|
||||
mark 2 tcp dport 10166 tcp dport set 10168 notrack
|
||||
}
|
||||
chain gbmcbr_nat_output {
|
||||
type filter hook output priority -300;
|
||||
tcp sport 10167 tcp sport set 10166 notrack
|
||||
tcp sport 10168 tcp sport set 10166 notrack
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
table bridge filter {
|
||||
chain gbmc_br_prerouting {
|
||||
type filter hook prerouting priority 0;
|
||||
iifname != gbmcbr accept
|
||||
# Sometimes our links are over NCSI and we don't want to broadcast
|
||||
# those packets over the entire bridge. They are only relevant P2P.
|
||||
ether type 0x88F8 drop
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
chain gbmc_br_input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
iifname != gbmcbr accept
|
||||
mark 0xff drop
|
||||
ct state established accept
|
||||
jump gbmc_br_int_input
|
||||
jump gbmc_br_pub_input
|
||||
reject
|
||||
}
|
||||
set gbmc_br_int_addrs {
|
||||
type ipv6_addr;
|
||||
flags interval
|
||||
elements = {
|
||||
ff00::/8,
|
||||
fe80::/64,
|
||||
fdb5:0481:10ce::/64,
|
||||
}
|
||||
}
|
||||
chain gbmc_br_int_input {
|
||||
ip6 daddr @gbmc_br_int_addrs accept
|
||||
ip6 saddr @gbmc_br_int_addrs accept
|
||||
}
|
||||
chain gbmc_br_pub_input {
|
||||
ip6 nexthdr icmpv6 accept
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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.
|
||||
|
||||
[ -n "${gbmc_psu_hardreset-}" ] && return
|
||||
|
||||
gbmc_psu_hardreset_needed=
|
||||
|
||||
gbmc_psu_hardreset_hook() {
|
||||
# We don't always need a powercycle, allow skipping
|
||||
if [ -z "${gbmc_psu_hardreset_needed-}" ]; then
|
||||
echo "Skipping tray powercycle" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Powercycling" >&2
|
||||
systemctl start gbmc-psu-hardreset.target || return
|
||||
|
||||
# Ensure that we don't continue the DHCP process while waiting for the
|
||||
# powercycle.
|
||||
exit 0
|
||||
}
|
||||
|
||||
GBMC_BR_DHCP_HOOKS+=(gbmc_psu_hardreset_hook)
|
||||
|
||||
gbmc_psu_hardreset=1
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=gBMC DHCP Client terminator
|
||||
After=network.target
|
||||
StartLimitIntervalSec=10
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
ExecStart=/usr/libexec/gbmc-br-dhcp-term.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
# Wait until a well known service is network available
|
||||
echo 'Waiting for network reachability' >&2
|
||||
while true; do
|
||||
before=$SECONDS
|
||||
addrs="$(ip addr show gbmcbr | grep '^ *inet6' | awk '{print $2}')"
|
||||
for addr in $addrs; do
|
||||
# Remove the prefix length
|
||||
ip="${addr%/*}"
|
||||
ip_to_bytes ip_bytes "$ip" || continue
|
||||
# Ignore ULAs and non-gBMC addresses
|
||||
(( ip_bytes[0] & 0xfc == 0xfc || ip_bytes[8] != 0xfd )) && continue
|
||||
# Only allow for the short, well known addresses <pfx>:fd01:: and not
|
||||
# <pfx>:fd00:83c1:292d:feef. Otherwise, powercycle may be unavailable.
|
||||
(( ip_bytes[9] == 0 )) && continue
|
||||
for i in {10..15}; do
|
||||
(( ip_bytes[i] != 0 )) && continue 2
|
||||
done
|
||||
echo "Trying reachability from $ip" >&2
|
||||
for i in {0..5}; do
|
||||
ping -I "$ip" -c 1 -W 1 2001:4860:4860::8888 >/dev/null 2>&1 && break 3
|
||||
sleep 1
|
||||
done
|
||||
done
|
||||
# Ensure we only complete the addr lookup loop every 10s
|
||||
tosleep=$((before + 10 - SECONDS))
|
||||
if (( tosleep > 0 )); then
|
||||
sleep "$tosleep"
|
||||
fi
|
||||
done
|
||||
|
||||
# We need to guarantee we wait at least 5 minutes from reachable in
|
||||
# case networking just came up
|
||||
wait_min=5
|
||||
echo "Network is reachable, waiting $wait_min min" >&2
|
||||
sleep $((60 * wait_min))
|
||||
|
||||
get_dhcp_unit_json() {
|
||||
busctl -j call \
|
||||
org.freedesktop.systemd1 \
|
||||
/org/freedesktop/systemd1/unit/gbmc_2dbr_2ddhcp_2eservice \
|
||||
org.freedesktop.DBus.Properties \
|
||||
GetAll s org.freedesktop.systemd1.Unit
|
||||
}
|
||||
|
||||
# Follow the process and make sure it idles for at least 5 minutes before
|
||||
# shutting down. This allows for failures and retries to happen.
|
||||
while true; do
|
||||
json="$(get_dhcp_unit_json)" || exit
|
||||
last_ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
|
||||
if pid="$(cat /run/gbmc-br-dhcp.pid 2>/dev/null)"; then
|
||||
# If the DHCP configuration process is running, wait for it to finish
|
||||
echo "DHCP still running ($pid), waiting" >&2
|
||||
while [[ -e /proc/$pid ]]; do
|
||||
sleep 1
|
||||
done
|
||||
# Wait for systemd to detect the process state change
|
||||
while true; do
|
||||
json="$(get_dhcp_unit_json)" || exit
|
||||
ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
|
||||
(( ms != last_ms )) && break
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
|
||||
echo 'Checking DHCP Active State' >&2
|
||||
json="$(get_dhcp_unit_json)" || exit
|
||||
activestr="$(echo "$json" | jq -r '.data[0].ActiveState.data')"
|
||||
|
||||
# The process is already stopped, we are done
|
||||
[[ "$activestr" == 'inactive' ]] && exit
|
||||
|
||||
# If the process is running, give it at least 5 minutes from when it started
|
||||
cur_s="$(cut -d' ' -f1 /proc/uptime)"
|
||||
# Remove floating point if applied since bash can't perform float arithmetic
|
||||
cur_s="${cur_s%.*}"
|
||||
if [[ "$activestr" == 'active' ]]; then
|
||||
active_ms="$(echo "$json" | jq -r '.data[0].ActiveEnterTimestampMonotonic.data')"
|
||||
else
|
||||
active_ms=$((cur_s*1000*1000))
|
||||
fi
|
||||
w=$((active_ms/1000/1000 + (wait_min*60) - cur_s))
|
||||
[ "$w" -lt 0 ] && break
|
||||
echo "Waiting ${w}s for DHCP process" >&2
|
||||
sleep "$w"
|
||||
done
|
||||
|
||||
echo "Stopping DHCP processing" >&2
|
||||
systemctl stop --no-block gbmc-br-dhcp
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=gBMC DHCP Client
|
||||
After=network.target
|
||||
StartLimitIntervalSec=10
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
ExecCondition=/bin/bash -c "! /bin/systemctl is-active -q dhcp-done@*"
|
||||
ExecStart=/usr/bin/udhcpc6 -f -q -O fqdn -O bootfile_url -O bootfile_param -i gbmcbr -s /usr/libexec/gbmc-br-dhcp.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/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.
|
||||
|
||||
# A list of functions which get executed for each bound DHCP lease.
|
||||
# These are configured by the files included below.
|
||||
# Shellcheck does not understand how this gets referenced
|
||||
# shellcheck disable=SC2034
|
||||
GBMC_BR_DHCP_HOOKS=()
|
||||
|
||||
# A dict of outstanding items that should prevent DHCP completion
|
||||
declare -A GBMC_BR_DHCP_OUTSTANDING=()
|
||||
|
||||
# SC can't find this path during repotest
|
||||
# shellcheck disable=SC1091
|
||||
source /usr/share/network/lib.sh || exit
|
||||
# SC can't find this path during repotest
|
||||
# shellcheck disable=SC1091
|
||||
source /usr/share/gbmc-br-lib.sh || exit
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# hooks that are executed after each event.
|
||||
gbmc_br_source_dir /usr/share/gbmc-br-dhcp || exit
|
||||
|
||||
# Write out the current PID and cleanup when complete
|
||||
trap 'rm -f /run/gbmc-br-dhcp.pid' EXIT
|
||||
echo "$$" >/run/gbmc-br-dhcp.pid
|
||||
|
||||
if [ "$1" = bound ]; then
|
||||
# Variable is from the environment via udhcpc6
|
||||
# shellcheck disable=SC2154
|
||||
echo "DHCPv6(gbmcbr): $ipv6/128" >&2
|
||||
|
||||
pfx_bytes=()
|
||||
ip_to_bytes pfx_bytes "$ipv6"
|
||||
# Ensure we are a BMC and have a suffix nibble, the 0th index is reserved
|
||||
if (( pfx_bytes[8] != 0xfd || pfx_bytes[9] & 0xf == 0 )); then
|
||||
echo "Invalid address" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Ensure we don't have more than a /80 address
|
||||
for (( i = 10; i < 16; ++i )); do
|
||||
if (( pfx_bytes[i] != 0 )); then
|
||||
echo "Invalid address" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
gbmc_br_set_ip "$pfx" || exit
|
||||
|
||||
if [ -n "${fqdn-}" ]; then
|
||||
echo "Using hostname $fqdn" >&2
|
||||
hostnamectl set-hostname "$fqdn" || true
|
||||
fi
|
||||
|
||||
gbmc_br_run_hooks GBMC_BR_DHCP_HOOKS || exit
|
||||
|
||||
# If any of our hooks had expectations we should fail here
|
||||
if [ "${#GBMC_BR_DHCP_OUTSTANDING[@]}" -gt 0 ]; then
|
||||
echo "Not done with DHCP process: ${!GBMC_BR_DHCP_OUTSTANDING[*]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure that the installer knows we have completed processing DHCP by
|
||||
# running a service that reports completion
|
||||
echo 'Start DHCP Done' >&2
|
||||
systemctl start dhcp-done@DONE --no-block
|
||||
fi
|
||||
@@ -0,0 +1,5 @@
|
||||
[Service]
|
||||
ExecStart=/usr/libexec/gbmc-br-ensure-ra.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/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.
|
||||
|
||||
# Every 30 seconds, send out an RA so that the kernel will receive a response.
|
||||
# This ensures that all BMCs (even ones that think they are routers) get updated
|
||||
# information from the other systems on the network.
|
||||
w=30
|
||||
while true; do
|
||||
start=$SECONDS
|
||||
rdisc6 -m gbmcbr -r 1 -w $(( w * 1000 )) >/dev/null 2>/dev/null
|
||||
# If rdisc6 exits early we still want to wait the full `w` time before
|
||||
# starting again.
|
||||
(( timeout = start + w - SECONDS ))
|
||||
sleep $(( timeout < 0 ? 0 : timeout ))
|
||||
done
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/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.
|
||||
|
||||
[[ -n ${gbmc_br_from_ra_lib-} ]] && return
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_br_from_ra_init=
|
||||
gbmc_br_from_ra_mac=
|
||||
declare -A gbmc_br_from_ra_pfxs=()
|
||||
declare -A gbmc_br_from_ra_prev_addrs=()
|
||||
|
||||
gbmc_br_from_ra_update() {
|
||||
[[ -n $gbmc_br_from_ra_init && -n $gbmc_br_from_ra_mac ]] || return
|
||||
|
||||
local pfx
|
||||
for pfx in "${!gbmc_br_from_ra_pfxs[@]}"; do
|
||||
local cidr
|
||||
if ! cidr="$(ip_pfx_to_cidr "$pfx")"; then
|
||||
unset 'gbmc_br_from_ra_pfxs[$pfx]'
|
||||
continue
|
||||
fi
|
||||
if (( cidr == 80 )); then
|
||||
local sfx
|
||||
if ! sfx="$(mac_to_eui48 "$gbmc_br_from_ra_mac")"; then
|
||||
unset 'gbmc_br_from_ra_pfxs[$pfx]'
|
||||
continue
|
||||
fi
|
||||
local addr
|
||||
if ! addr="$(ip_pfx_concat "$pfx" "$sfx")"; then
|
||||
unset 'gbmc_br_from_ra_pfxs[$pfx]'
|
||||
continue
|
||||
fi
|
||||
else
|
||||
unset 'gbmc_br_from_ra_pfxs[$pfx]'
|
||||
continue
|
||||
fi
|
||||
local valid="${gbmc_br_from_ra_pfxs["$pfx"]}"
|
||||
if (( valid > 0 )); then
|
||||
if [[ -z ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
|
||||
echo "gBMC Bridge RA Addr Add: $addr" >&2
|
||||
gbmc_br_from_ra_prev_addrs["$addr"]=1
|
||||
fi
|
||||
ip addr replace "$addr" dev gbmcbr noprefixroute
|
||||
else
|
||||
if [[ -n ${gbmc_br_from_ra_prev_addrs["$addr"]-} ]]; then
|
||||
echo "gBMC Bridge RA Addr Del: $addr" >&2
|
||||
unset 'gbmc_br_from_ra_prev_addrs[$addr]'
|
||||
fi
|
||||
ip addr del "$addr" dev gbmcbr
|
||||
unset 'gbmc_br_from_ra_pfxs[$pfx]'
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
gbmc_br_from_ra_hook() {
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $change == init ]]; then
|
||||
gbmc_br_from_ra_init=1
|
||||
gbmc_ip_monitor_defer
|
||||
elif [[ $change == defer ]]; then
|
||||
gbmc_br_from_ra_update
|
||||
elif [[ $change == route && $route != *' via '* ]] &&
|
||||
[[ $route =~ ^(.* dev gbmcbr proto ra .*)( +expires +([^ ]+)sec).*$ ]]; then
|
||||
pfx="${route%% *}"
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $action == add ]]; then
|
||||
gbmc_br_from_ra_pfxs["$pfx"]="${BASH_REMATCH[3]}"
|
||||
gbmc_ip_monitor_defer
|
||||
elif [[ $action == del ]]; then
|
||||
gbmc_br_from_ra_pfxs["$pfx"]=0
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
elif [[ $change == link && $intf == gbmcbr ]]; then
|
||||
rdisc6 -m gbmcbr -r 1 -w 100 >/dev/null 2>&1
|
||||
if [[ $action == add && $mac != "$gbmc_br_from_ra_mac" ]]; then
|
||||
gbmc_br_from_ra_mac="$mac"
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
if [[ $action == del && $mac == "$gbmc_br_from_ra_mac" ]]; then
|
||||
gbmc_br_from_ra_mac=
|
||||
gbmc_ip_monitor_defer
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_from_ra_hook)
|
||||
|
||||
gbmc_br_from_ra_lib=1
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/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.
|
||||
|
||||
[[ -n ${gbmc_br_gw_src_lib-} ]] && return
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_br_gw_src_ip_stateful=
|
||||
gbmc_br_gw_src_ip_stateless=
|
||||
declare -A gbmc_br_gw_src_routes=()
|
||||
gbmc_br_gw_defgw=
|
||||
|
||||
gbmc_br_set_router() {
|
||||
local defgw=
|
||||
local route
|
||||
for route in "${!gbmc_br_gw_src_routes[@]}"; do
|
||||
if [[ $route != *' dev gbmcbr '* ]]; then
|
||||
defgw=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
[[ $defgw == "$gbmc_br_gw_defgw" ]] && return
|
||||
gbmc_br_gw_defgw="$defgw"
|
||||
|
||||
local files=(/run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-defgw.conf)
|
||||
if [[ -n $defgw ]]; then
|
||||
local file
|
||||
for file in "${files[@]}"; do
|
||||
mkdir -p "$(dirname "$file")"
|
||||
printf '[IPv6PrefixDelegation]\nRouterLifetimeSec=30\n' >"$file"
|
||||
done
|
||||
else
|
||||
rm -f "${files[@]}"
|
||||
fi
|
||||
|
||||
if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then
|
||||
networkctl reload && networkctl reconfigure gbmcbr
|
||||
fi
|
||||
}
|
||||
|
||||
gbmc_br_gw_src_update() {
|
||||
local gbmc_br_gw_src_ip="${gbmc_br_gw_src_ip_stateful:-$gbmc_br_gw_src_ip_stateless}"
|
||||
[[ -n $gbmc_br_gw_src_ip ]] || return
|
||||
|
||||
local route
|
||||
for route in "${!gbmc_br_gw_src_routes[@]}"; do
|
||||
[[ $route != *" src $gbmc_br_gw_src_ip "* ]] || continue
|
||||
echo "gBMC Bridge Updating GW source [$gbmc_br_gw_src_ip]: $route" >&2
|
||||
# shellcheck disable=SC2086
|
||||
ip route change $route src "$gbmc_br_gw_src_ip" && \
|
||||
unset 'gbmc_br_gw_src_routes[$route]'
|
||||
done
|
||||
}
|
||||
|
||||
gbmc_br_gw_src_hook() {
|
||||
# We only want to match default gateway routes that are dynamic
|
||||
# (have an expiration time). These will be updated with our preferred
|
||||
# source.
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $change == route && $route == 'default '*':'* ]]; then
|
||||
if [[ $route =~ ^(.*)( +expires +[^ ]+)(.*)$ ]]; then
|
||||
route="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
|
||||
fi
|
||||
if [[ $action == add && -z ${gbmc_br_gw_src_routes["$route"]} ]]; then
|
||||
gbmc_br_gw_src_routes["$route"]=1
|
||||
gbmc_br_gw_src_update
|
||||
gbmc_br_set_router
|
||||
elif [[ $action == del && -n "${gbmc_br_gw_src_routes["$route"]}" ]]; then
|
||||
unset 'gbmc_br_gw_src_routes[$route]'
|
||||
gbmc_br_gw_src_update
|
||||
gbmc_br_set_router
|
||||
fi
|
||||
# Match only global IP addresses on the bridge that match the BMC stateless
|
||||
# prefix (<mpfx>:fd00:). So 2002:af4:3480:2248:fd00:6345:3069:9186 would be
|
||||
# matched as the preferred source IP for outoging traffic.
|
||||
elif [[ $change == addr && $intf == gbmcbr && $scope == global ]] &&
|
||||
[[ $fam == inet6 && $flags != *tentative* ]]; then
|
||||
local ip_bytes=()
|
||||
if ! ip_to_bytes ip_bytes "$ip"; then
|
||||
echo "gBMC Bridge Ensure RA Invalid IP: $ip" >&2
|
||||
return 1
|
||||
fi
|
||||
# Ignore ULAs and non-gBMC addresses
|
||||
if (( ip_bytes[0] & 0xfe == 0xfc || ip_bytes[8] != 0xfd )); then
|
||||
return 0
|
||||
fi
|
||||
if (( ip_bytes[9] & 0x0f != 0 )); then
|
||||
local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateful
|
||||
else
|
||||
local -n gbmc_br_gw_src_ip=gbmc_br_gw_src_ip_stateless
|
||||
fi
|
||||
if [[ $action == add && $ip != "$gbmc_br_gw_src_ip" ]]; then
|
||||
gbmc_br_gw_src_ip="$ip"
|
||||
gbmc_br_gw_src_update
|
||||
fi
|
||||
if [[ $action == del && $ip == "$gbmc_br_gw_src_ip" ]]; then
|
||||
gbmc_br_gw_src_ip=
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_gw_src_hook)
|
||||
|
||||
gbmc_br_gw_src_lib=1
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2022 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.
|
||||
|
||||
[ -n "${gbmc_br_lib_init-}" ] && return
|
||||
|
||||
# SC can't find this path during repotest
|
||||
# shellcheck disable=SC1091
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
# A list of functions which get executed for each configured IP.
|
||||
# These are configured by the files included below.
|
||||
# Shellcheck does not understand how this gets referenced
|
||||
# shellcheck disable=SC2034
|
||||
GBMC_BR_LIB_SET_IP_HOOKS=()
|
||||
|
||||
gbmc_br_source_dir() {
|
||||
local dir="$1"
|
||||
|
||||
local file
|
||||
while read -r -d $'\0' file; do
|
||||
# SC doesn't like dynamic source loading
|
||||
# shellcheck disable=SC1090
|
||||
source "$file" || return
|
||||
done < <(shopt -s nullglob; for f in "$dir"/*.sh; do printf '%s\0' "$f"; done)
|
||||
}
|
||||
|
||||
# Load configurations from a known location in the filesystem to populate
|
||||
# hooks that are executed after each event.
|
||||
gbmc_br_source_dir /usr/share/gbmc-br-lib || exit
|
||||
|
||||
gbmc_br_run_hooks() {
|
||||
local -n hookvar="$1"
|
||||
shift
|
||||
local hook
|
||||
for hook in "${hookvar[@]}"; do
|
||||
"$hook" "$@" || return
|
||||
done
|
||||
}
|
||||
|
||||
gbmc_br_reload() {
|
||||
if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then
|
||||
networkctl reload && networkctl reconfigure gbmcbr
|
||||
fi
|
||||
}
|
||||
|
||||
gbmc_br_no_ip() {
|
||||
echo "Runtime removing gbmcbr IP" >&2
|
||||
rm -f /run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-public.conf
|
||||
gbmc_br_reload
|
||||
}
|
||||
|
||||
gbmc_br_reload_ip() {
|
||||
local ip="${1-}"
|
||||
|
||||
if [ -z "$ip" ] && ! ip="$(cat /var/google/gbmc-br-ip 2>/dev/null)"; then
|
||||
echo "Ignoring unconfigured IP" >&2
|
||||
gbmc_br_no_ip
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove legacy network configuration
|
||||
rm -rf /etc/systemd/network/{00,}-bmc-gbmcbr.network.d
|
||||
|
||||
local pfx_bytes=()
|
||||
if ! ip_to_bytes pfx_bytes "$ip"; then
|
||||
echo "Ignoring Invalid IPv6: $ip" >&2
|
||||
gbmc_br_no_ip
|
||||
return 0
|
||||
fi
|
||||
|
||||
local pfx
|
||||
pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
(( pfx_bytes[9] &= 0xf0 ))
|
||||
local stateless_pfx
|
||||
stateless_pfx="$(ip_bytes_to_str pfx_bytes)"
|
||||
local contents
|
||||
read -r -d '' contents <<EOF
|
||||
[Network]
|
||||
Address=$pfx/128
|
||||
[IPv6Prefix]
|
||||
Prefix=$stateless_pfx/80
|
||||
PreferredLifetimeSec=60
|
||||
ValidLifetimeSec=60
|
||||
[IPv6RoutePrefix]
|
||||
Route=$pfx/80
|
||||
LifetimeSec=60
|
||||
[Route]
|
||||
Destination=$stateless_pfx/76
|
||||
Type=unreachable
|
||||
Metric=1024
|
||||
EOF
|
||||
echo "Runtime setting gbmcbr IP: $pfx" >&2
|
||||
|
||||
local file
|
||||
for file in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/50-public.conf; do
|
||||
mkdir -p "$(dirname "$file")"
|
||||
printf '%s' "$contents" >"$file"
|
||||
done
|
||||
|
||||
gbmc_br_reload
|
||||
}
|
||||
|
||||
gbmc_br_set_ip() {
|
||||
local ip="${1-}"
|
||||
local old_ip=
|
||||
if [ -n "$ip" ]; then
|
||||
old_ip="$(cat /var/google/gbmc-br-ip 2>/dev/null)"
|
||||
[ "$old_ip" == "$ip" ] && return
|
||||
mkdir -p /var/google || return
|
||||
echo "$ip" >/var/google/gbmc-br-ip || return
|
||||
else
|
||||
[ ! -f "/var/google/gbmc-br-ip" ] && return
|
||||
rm -rf /var/google/gbmc-br-ip
|
||||
fi
|
||||
|
||||
gbmc_br_run_hooks GBMC_BR_LIB_SET_IP_HOOKS "$ip" || return
|
||||
|
||||
gbmc_br_reload_ip "$ip"
|
||||
}
|
||||
|
||||
gbmc_br_lib_init=1
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Before=gbmc-ip-monitor.service
|
||||
Before=systemd-networkd.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash -c 'source /usr/share/gbmc-br-lib.sh && gbmc_br_reload_ip'
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/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.
|
||||
|
||||
[[ -n ${gbmc_br_nft_lib-} ]] && return
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_br_nft_pfx=
|
||||
|
||||
gbmc_br_nft_update() {
|
||||
printf 'gBMC Bridge input firewall for %s\n' \
|
||||
"${gbmc_br_nft_pfx:-(deleted)}" >&2
|
||||
|
||||
local contents=
|
||||
contents+='table inet filter {'$'\n'
|
||||
contents+=' chain gbmc_br_int_input {'$'\n'
|
||||
if [[ -n ${gbmc_br_nft_pfx-} ]]; then
|
||||
contents+=" ip6 saddr $gbmc_br_nft_pfx"
|
||||
contents+=" ip6 daddr $gbmc_br_nft_pfx accept"$'\n'
|
||||
fi
|
||||
contents+=' }'$'\n'
|
||||
contents+='}'$'\n'
|
||||
|
||||
local rfile=/run/nftables/40-gbmc-br-int.rules
|
||||
mkdir -p "$(dirname "$rfile")"
|
||||
printf '%s' "$contents" >"$rfile"
|
||||
|
||||
# shellcheck disable=SC2015
|
||||
systemctl reset-failed nftables && systemctl --no-block reload-or-restart nftables || true
|
||||
}
|
||||
|
||||
gbmc_br_nft_hook() {
|
||||
# Match only global IP addresses on the bridge that match the BMC prefix
|
||||
# (<mpfx>:fdxx:). So 2002:af4:3480:2248:fd02:6345:3069:9186 would become
|
||||
# a 2002:af4:3480:2248:fd00/76 rule.
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $change == addr && $intf == gbmcbr && $scope == global ]] &&
|
||||
[[ $fam == inet6 && $flags != *tentative* ]]; then
|
||||
local ip_bytes=()
|
||||
if ! ip_to_bytes ip_bytes "$ip"; then
|
||||
echo "gBMC Bridge NFT Invalid IP: $ip" >&2
|
||||
return 1
|
||||
fi
|
||||
if (( ip_bytes[8] != 0xfd )); then
|
||||
return 0
|
||||
fi
|
||||
local i
|
||||
for (( i=9; i<16; i++ )); do
|
||||
ip_bytes["$i"]=0
|
||||
done
|
||||
pfx="$(ip_bytes_to_str ip_bytes)/76"
|
||||
if [[ $action == add && $pfx != "$gbmc_br_nft_pfx" ]]; then
|
||||
gbmc_br_nft_pfx="$pfx"
|
||||
gbmc_br_nft_update
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_nft_hook)
|
||||
|
||||
gbmc_br_nft_lib=1
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/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.
|
||||
|
||||
[[ -n ${gbmc_br_ula_lib-} ]] && return
|
||||
|
||||
# shellcheck source=meta-google/recipes-google/networking/network-sh/lib.sh
|
||||
source /usr/share/network/lib.sh || exit
|
||||
|
||||
gbmc_br_ula_init=
|
||||
gbmc_br_ula_mac=
|
||||
|
||||
gbmc_br_ula_update() {
|
||||
[[ -n $gbmc_br_ula_init ]] || return
|
||||
|
||||
echo "gBMC Bridge ULA MAC: ${gbmc_br_ula_mac:-(deleted)}" >&2
|
||||
|
||||
local addr=
|
||||
contents='[Network]'$'\n'
|
||||
if [[ -n $gbmc_br_ula_mac ]]; then
|
||||
local sfx
|
||||
if sfx="$(mac_to_eui64 "$gbmc_br_ula_mac")" &&
|
||||
addr="$(ip_pfx_concat "fdb5:0481:10ce::/64" "$sfx")"; then
|
||||
contents+="Address=$addr"$'\n'
|
||||
fi
|
||||
fi
|
||||
|
||||
local netfile
|
||||
for netfile in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/60-ula.conf; do
|
||||
mkdir -p "$(dirname "$netfile")"
|
||||
printf '%s' "$contents" >"$netfile"
|
||||
done
|
||||
|
||||
# Ensure that systemd-networkd performs a reconfiguration as it doesn't
|
||||
# currently check the mtime of drop-in files.
|
||||
touch -c /lib/systemd/network/*-bmc-gbmcbr.network
|
||||
|
||||
if [[ $(systemctl is-active systemd-networkd) != inactive ]]; then
|
||||
networkctl reload
|
||||
networkctl reconfigure gbmcbr
|
||||
fi
|
||||
}
|
||||
|
||||
gbmc_br_ula_hook() {
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $change == init ]]; then
|
||||
gbmc_br_ula_init=1
|
||||
gbmc_br_ula_update
|
||||
elif [[ $change == link && $intf == gbmcbr ]]; then
|
||||
if [[ $action == add && $mac != "$gbmc_br_ula_mac" ]]; then
|
||||
gbmc_br_ula_mac="$mac"
|
||||
gbmc_br_ula_update
|
||||
fi
|
||||
if [[ $action == del && $mac == "$gbmc_br_ula_mac" ]]; then
|
||||
gbmc_br_ula_mac=
|
||||
gbmc_br_ula_update
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
GBMC_IP_MONITOR_HOOKS+=(gbmc_br_ula_hook)
|
||||
|
||||
gbmc_br_ula_lib=1
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2023 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.
|
||||
|
||||
# stop dhcp term service to prevent race condition
|
||||
systemctl is-active --quiet gbmc-br-dhcp-term && systemctl stop gbmc-br-dhcp-term
|
||||
|
||||
# start the dhcp service
|
||||
systemctl start gbmc-br-dhcp
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
<service-group>
|
||||
<name>@NAME@</name>
|
||||
<service>
|
||||
<type>_ipmi._udp</type>
|
||||
<port>623</port>
|
||||
<txt-record>Machine=@MACHINE@</txt-record>
|
||||
@EXTRA_ATTRS@
|
||||
</service>
|
||||
</service-group>
|
||||
@@ -0,0 +1,35 @@
|
||||
SUMMARY = "Allows hooking netlink events to perform network actions"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
SRC_URI += " \
|
||||
file://gbmc-ip-monitor.service \
|
||||
file://gbmc-ip-monitor.sh \
|
||||
file://gbmc-ip-monitor-test.sh \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
DEPENDS += "test-sh"
|
||||
|
||||
RDEPENDS:${PN} += " \
|
||||
bash \
|
||||
iproute2 \
|
||||
"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += "gbmc-ip-monitor.service"
|
||||
|
||||
do_compile() {
|
||||
SYSROOT="$PKG_CONFIG_SYSROOT_DIR" bash gbmc-ip-monitor-test.sh || exit
|
||||
}
|
||||
|
||||
do_install:append() {
|
||||
install -d -m0755 ${D}${libexecdir}
|
||||
install -m0755 gbmc-ip-monitor.sh ${D}${libexecdir}/
|
||||
|
||||
install -d -m0755 ${D}${systemd_system_unitdir}
|
||||
install -m0644 gbmc-ip-monitor.service ${D}${systemd_system_unitdir}/
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
PR = "r1"
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
RDEPENDS:${PN} += "iperf3"
|
||||
|
||||
SRC_URI += "file://iperf3.service"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += "iperf3.service"
|
||||
|
||||
do_install() {
|
||||
# Install service definitions
|
||||
install -d -m 0755 ${D}${systemd_system_unitdir}
|
||||
install -m 0644 ${WORKDIR}/iperf3.service ${D}${systemd_system_unitdir}
|
||||
}
|
||||
|
||||
# Allow IPERF3 to run on the gbmcbr node on DEV builds
|
||||
do_install:append:dev() {
|
||||
nftables_dir=${D}${sysconfdir}/nftables
|
||||
rules=$nftables_dir/50-gbmc-iperf3-dev.rules
|
||||
install -d -m0755 $nftables_dir
|
||||
echo 'table inet filter {' >"$rules"
|
||||
echo ' chain gbmc_br_pub_input {' >>"$rules"
|
||||
echo ' tcp dport 5201 accept' >>"$rules"
|
||||
echo ' }' >>"$rules"
|
||||
echo '}' >>"$rules"
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
SUMMARY = "Configures MAC addresses on a gBMC system"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
inherit systemd
|
||||
|
||||
SRC_URI += " \
|
||||
file://gbmc-mac-config.service \
|
||||
file://gbmc-mac-config.sh.in \
|
||||
"
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
RDEPENDS:${PN} += " \
|
||||
bash \
|
||||
ipmi-fru-sh \
|
||||
"
|
||||
|
||||
FILES:${PN} += "${systemd_unitdir}"
|
||||
|
||||
SYSTEMD_SERVICE:${PN} += "gbmc-mac-config.service"
|
||||
|
||||
GBMC_MAC_EEPROM_OF_NAME ?= ""
|
||||
|
||||
# Maps the MAC address offset from the base address to an interface name
|
||||
# in bash associative array syntax.
|
||||
# Ex. "[0]=eth0 [2]=eth2"
|
||||
GBMC_MAC_IF_MAP ?= ""
|
||||
|
||||
do_install:append() {
|
||||
if [ -z '${GBMC_MAC_EEPROM_OF_NAME}' ]; then
|
||||
echo 'Missing GBMC_MAC_EEPROM_OF_NAME' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build time dictionary sanity check
|
||||
bash -c "declare -A dict=(${GBMC_MAC_IF_MAP})"
|
||||
|
||||
sed gbmc-mac-config.sh.in \
|
||||
-e 's#@EEPROM@#${GBMC_MAC_EEPROM_OF_NAME}#' \
|
||||
-e "s#@NUM_TO_INTFS@#${GBMC_MAC_IF_MAP}#" \
|
||||
>gbmc-mac-config.sh
|
||||
|
||||
install -d -m0755 ${D}${libexecdir}
|
||||
install -m0755 gbmc-mac-config.sh ${D}${libexecdir}/
|
||||
|
||||
install -d -m0755 ${D}${systemd_system_unitdir}
|
||||
install -m0644 gbmc-mac-config.service ${D}${systemd_system_unitdir}/
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
SUMMARY = "Rename the network device name"
|
||||
PR = "r1"
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
GBMC_ETHER_MAP ?= ""
|
||||
|
||||
inherit systemd
|
||||
|
||||
S = "${WORKDIR}"
|
||||
|
||||
FILES:${PN} += "${systemd_unitdir}"
|
||||
|
||||
do_install() {
|
||||
netdir=${D}${systemd_unitdir}/network
|
||||
install -d -m0755 $netdir
|
||||
|
||||
# install dev renaming files if any
|
||||
if [ -z "${GBMC_ETHER_MAP}"]; then
|
||||
return
|
||||
fi
|
||||
devmap="${GBMC_ETHER_MAP}"
|
||||
for str in $devmap
|
||||
do
|
||||
devaddr="$(echo "${str}" | cut -d'|' -f1)"
|
||||
devname="$(echo "${str}" | cut -d'|' -f2)"
|
||||
echo "[Match]" > ${WORKDIR}/30-netdev-${devname}.link
|
||||
echo "Path=*-${devaddr}" >> ${WORKDIR}/30-netdev-${devname}.link
|
||||
echo "[Link]" >> ${WORKDIR}/30-netdev-${devname}.link
|
||||
echo "Name=${devname}" >> ${WORKDIR}/30-netdev-${devname}.link
|
||||
install -m0644 ${WORKDIR}/30-netdev-${devname}.link ${netdir}
|
||||
done
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
divert(-1)
|
||||
define(`HOST_MAC_ARG', `ifelse($1, `invalid', `',
|
||||
ifelse($1, `', `',
|
||||
` --host-mac "$1"'))')
|
||||
|
||||
define(`DEV_MAC_ARG', `ifelse($1, `invalid', `',
|
||||
ifelse($1, `', `',
|
||||
` --dev-mac "$1"'))')
|
||||
|
||||
divert(0)dnl
|
||||
dnl
|
||||
[Unit]
|
||||
Description=USB Gadget
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=M_SCRIPT_INSTALL_DIR/usb_network.sh \
|
||||
--product-id "M_BMC_USB_PRODUCT_ID" \
|
||||
--product-name "M_BMC_USB_PRODUCT_NAME" \
|
||||
--dev-type "M_BMC_USB_TYPE" \
|
||||
HOST_MAC_ARG(M_BMC_USB_HOST_MAC) \
|
||||
DEV_MAC_ARG(M_BMC_USB_DEV_MAC) \
|
||||
--iface-name "M_BMC_USB_IFACE" \
|
||||
--bind-device "M_BMC_USB_BIND_DEV"
|
||||
ExecStop=M_SCRIPT_INSTALL_DIR/usb_network.sh stop \
|
||||
--dev-type "M_BMC_USB_TYPE" \
|
||||
--iface-name "M_BMC_USB_IFACE"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,231 @@
|
||||
#!/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.
|
||||
|
||||
|
||||
# List of options the script accepts. Trailing column means that the option
|
||||
# requires an argument.
|
||||
ARGUMENT_LIST=(
|
||||
"help"
|
||||
"product-id:"
|
||||
"product-name:"
|
||||
"host-mac:"
|
||||
"bind-device:"
|
||||
"dev-mac:"
|
||||
"dev-type:"
|
||||
"gadget-dir-name:"
|
||||
"iface-name:"
|
||||
)
|
||||
|
||||
print_usage() {
|
||||
cat <<HELP
|
||||
$0 [OPTIONS] [stop|start]
|
||||
Create USB Gadget Configuration
|
||||
--product-id USB Product Id for the gadget.
|
||||
--product-name Product name string (en) for the gadget.
|
||||
--host-mac MAC address of the host part of the connection. Optional.
|
||||
--dev-mac MAC address of the device (gadget) part of the connection. Optional.
|
||||
--dev-type Type of gadget to instantiate. Default: "eem"
|
||||
--bind-device Name of the device to bind, as listed in /sys/class/udc/
|
||||
--gadget-dir-name Optional base name for gadget directory. Default: iface-name
|
||||
--iface-name name of the network interface.
|
||||
--help Print this help and exit.
|
||||
HELP
|
||||
}
|
||||
|
||||
gadget_start() {
|
||||
# Always provide a basic network configuration
|
||||
mkdir -p /run/systemd/network || return
|
||||
cat >/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
|
||||
[Match]
|
||||
Name=${IFACE_NAME}
|
||||
EOF
|
||||
|
||||
# Add the gbmcbr configuration if this is a relevant device
|
||||
if (( ID_VENDOR == 0x18d1 && ID_PRODUCT == 0x22b )); then
|
||||
cat >>/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
|
||||
[Network]
|
||||
Bridge=gbmcbr
|
||||
[Bridge]
|
||||
Cost=85
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Ignore any failures due to systemd being unavailable at boot
|
||||
networkctl reload || true
|
||||
|
||||
local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
|
||||
mkdir -p "${gadget_dir}" || return
|
||||
echo "${ID_VENDOR}" >"${gadget_dir}/idVendor" || return
|
||||
echo "${ID_PRODUCT}" >"${gadget_dir}/idProduct" || return
|
||||
|
||||
local str_en_dir="${gadget_dir}/strings/0x409"
|
||||
mkdir -p "${str_en_dir}" || return
|
||||
echo "${STR_EN_VENDOR}" >"${str_en_dir}/manufacturer" || return
|
||||
echo "${STR_EN_PRODUCT}" >"${str_en_dir}/product" || return
|
||||
|
||||
local config_dir="${gadget_dir}/configs/c.1"
|
||||
mkdir -p "${config_dir}" || return
|
||||
echo 100 > "${config_dir}/MaxPower" || return
|
||||
mkdir -p "${config_dir}/strings/0x409" || return
|
||||
echo "${DEV_TYPE^^}" > "${config_dir}/strings/0x409/configuration" || return
|
||||
|
||||
local func_dir="${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME}"
|
||||
mkdir -p "${func_dir}" || return
|
||||
|
||||
if [[ -n $HOST_MAC_ADDR ]]; then
|
||||
echo "${HOST_MAC_ADDR}" >"${func_dir}"/host_addr || return
|
||||
fi
|
||||
|
||||
if [[ -n $DEV_MAC_ADDR ]]; then
|
||||
echo "${DEV_MAC_ADDR}" >"${func_dir}"/dev_addr || return
|
||||
fi
|
||||
|
||||
ln -s "${func_dir}" "${config_dir}" || return
|
||||
|
||||
# This only works on kernel 5.12+, we have to ignore failures for now
|
||||
echo "$IFACE_NAME" >"${func_dir}"/ifname || true
|
||||
|
||||
echo "${BIND_DEVICE}" >"${gadget_dir}"/UDC || return
|
||||
# Try to reconfigure a few times in case we race with systemd-networkd
|
||||
local start=$SECONDS
|
||||
while (( SECONDS - start < 5 )); do
|
||||
local ifname
|
||||
ifname="$(<"${func_dir}"/ifname)" || return
|
||||
[ "${IFACE_NAME}" = "$ifname" ] && break
|
||||
ip link set dev "$ifname" down && \
|
||||
ip link set dev "$ifname" name "${IFACE_NAME}" && break
|
||||
sleep 1
|
||||
done
|
||||
ip link set dev "$IFACE_NAME" up || return
|
||||
}
|
||||
|
||||
gadget_stop() {
|
||||
local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
|
||||
rm -f "${gadget_dir}/configs/c.1/${DEV_TYPE}.${IFACE_NAME}"
|
||||
rmdir "${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME}" \
|
||||
"${gadget_dir}/configs/c.1/strings/0x409" \
|
||||
"${gadget_dir}/configs/c.1" \
|
||||
"${gadget_dir}/strings/0x409" \
|
||||
"${gadget_dir}" || true
|
||||
|
||||
rm -f /run/systemd/network/+-bmc-"${IFACE_NAME}".network
|
||||
networkctl reload || true
|
||||
}
|
||||
|
||||
opts="$(getopt \
|
||||
--longoptions "$(printf "%s," "${ARGUMENT_LIST[@]}")" \
|
||||
--name "$(basename "$0")" \
|
||||
--options "" \
|
||||
-- "$@"
|
||||
)"
|
||||
|
||||
eval set -- "$opts"
|
||||
|
||||
CONFIGFS_HOME=${CONFIGFS_HOME:-/sys/kernel/config}
|
||||
ID_VENDOR="0x18d1" # Google
|
||||
ID_PRODUCT=""
|
||||
STR_EN_VENDOR="Google"
|
||||
STR_EN_PRODUCT=""
|
||||
DEV_MAC_ADDR=""
|
||||
DEV_TYPE="eem"
|
||||
HOST_MAC_ADDR=""
|
||||
BIND_DEVICE=""
|
||||
ACTION="start"
|
||||
GADGET_DIR_NAME=""
|
||||
IFACE_NAME=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--product-id)
|
||||
ID_PRODUCT=$2
|
||||
shift 2
|
||||
;;
|
||||
--product-name)
|
||||
STR_EN_PRODUCT=$2
|
||||
shift 2
|
||||
;;
|
||||
--host-mac)
|
||||
HOST_MAC_ADDR=$2
|
||||
shift 2
|
||||
;;
|
||||
--dev-mac)
|
||||
DEV_MAC_ADDR=$2
|
||||
shift 2
|
||||
;;
|
||||
--dev-type)
|
||||
DEV_TYPE=$2
|
||||
shift 2
|
||||
;;
|
||||
--bind-device)
|
||||
BIND_DEVICE=$2
|
||||
shift 2
|
||||
;;
|
||||
--gadget-dir-name)
|
||||
GADGET_DIR_NAME=$2
|
||||
shift 2
|
||||
;;
|
||||
--iface-name)
|
||||
IFACE_NAME=$2
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
start)
|
||||
ACTION="start"
|
||||
shift 1
|
||||
break
|
||||
;;
|
||||
stop)
|
||||
ACTION="stop"
|
||||
shift 1
|
||||
break
|
||||
;;
|
||||
--)
|
||||
shift 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$GADGET_DIR_NAME" ]; then
|
||||
GADGET_DIR_NAME="$IFACE_NAME"
|
||||
fi
|
||||
|
||||
if [[ $ACTION == "stop" ]]; then
|
||||
gadget_stop
|
||||
else
|
||||
if [ -z "$ID_PRODUCT" ]; then
|
||||
echo "Product ID is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$IFACE_NAME" ]; then
|
||||
echo "Interface name is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$BIND_DEVICE" ]; then
|
||||
echo "Bind device is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rc=0
|
||||
gadget_start || rc=$?
|
||||
(( rc == 0 )) || gadget_stop || true
|
||||
exit $rc
|
||||
fi
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
#!/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.
|
||||
|
||||
|
||||
TEMPDIRS=()
|
||||
# Script under test
|
||||
SUT=$PWD/usb_network.sh
|
||||
|
||||
TEST_STATUS="OK"
|
||||
|
||||
test_setup() {
|
||||
echo -n "Testing $1 ..."
|
||||
FAKE_CONFIGFS="$(mktemp -d)"
|
||||
TEMPDIRS+=("${FAKE_CONFIGFS}")
|
||||
FAKE_GADGETFS="$FAKE_CONFIGFS"/usb_gadget
|
||||
mkdir -p "$FAKE_GADGETFS"
|
||||
}
|
||||
|
||||
test_teardown() {
|
||||
echo ${TEST_STATUS}
|
||||
rm -rf -- "${TEMPDIRS[@]}"
|
||||
TEMPDIRS=()
|
||||
}
|
||||
|
||||
test_fail() {
|
||||
echo -n " $* " >&2
|
||||
TEST_STATUS=FAIL
|
||||
|
||||
test_teardown
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_file_content() {
|
||||
local filename="$1"
|
||||
local expected_content="$2"
|
||||
|
||||
if [[ ! -f ${filename} ]]; then
|
||||
test_fail "File ${filename} does not exist!"
|
||||
fi
|
||||
|
||||
local actual_content
|
||||
actual_content=$(<"${filename}")
|
||||
if [[ $expected_content != "$actual_content" ]]; then
|
||||
test_fail "Expected ${expected_content}, got ${actual_content}"
|
||||
fi
|
||||
}
|
||||
|
||||
test_gadget_creation_with_defaults() {
|
||||
local extra_args=()
|
||||
local gadget_dir="$1"
|
||||
if [[ $gadget_dir == "" ]]; then
|
||||
gadget_dir="g1";
|
||||
else
|
||||
extra_args+=(--gadget-dir-name "${gadget_dir}")
|
||||
fi
|
||||
local product_name="Souvenier BMC"
|
||||
local product_id="0xcafe"
|
||||
local host_mac="ab:cd:ef:10:11:12"
|
||||
local dev_mac="12:11:10:ef:cd:ab"
|
||||
local bind_device="f80002000.udc"
|
||||
if ! CONFIGFS_HOME="${FAKE_CONFIGFS}" "${SUT}" --product-id "${product_id}" \
|
||||
--product-name "${product_name}" \
|
||||
--host-mac "${host_mac}" \
|
||||
--dev-mac "${dev_mac}" \
|
||||
--bind-device "${bind_device}" \
|
||||
"${extra_args[@]}"; then
|
||||
test_fail "${SUT} failed"
|
||||
fi
|
||||
|
||||
if [[ ! -d ${FAKE_GADGETFS}/${gadget_dir} ]]; then
|
||||
test_fail "Gadget was not created!"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idVendor" "0x18d1"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idProduct" "${product_id}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/manufacturer" "Google"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/product" "${product_name}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/MaxPower" "100"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/strings/0x409/configuration" "EEM"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0/dev_addr" "${dev_mac}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0/host_addr" "${host_mac}"
|
||||
|
||||
if [[ ! -d ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0 ]]; then
|
||||
test_fail "Function directory was not created"
|
||||
fi
|
||||
|
||||
local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/ee.usb0"
|
||||
if [[ ! -L ${func_link} ]]; then
|
||||
test_fail "Symlink to the function was not created in the config"
|
||||
fi
|
||||
|
||||
local link_dest
|
||||
link_dest="$(realpath "${func_link}")"
|
||||
if [[ $link_dest != "${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0" ]]; then
|
||||
test_fail "Symlink points to the wrong file/dir"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/UDC" "${bind_device}"
|
||||
}
|
||||
|
||||
test_gadget_creation_with_override() {
|
||||
mkdir -p "${FAKE_GADGETFS}"/g1/{strings,configs,functions}
|
||||
touch "${FAKE_GADGETFS}"/g1/{idVendor,idProduct}
|
||||
|
||||
test_gadget_creation_with_defaults
|
||||
}
|
||||
|
||||
test_gadget_stopping() {
|
||||
local extra_args=()
|
||||
local gadget_dir="$1"
|
||||
local iface_name="$2"
|
||||
if [[ $gadget_dir == "" ]]; then
|
||||
gadget_dir="g1";
|
||||
else
|
||||
extra_args+=(--gadget-dir-name "${gadget_dir}")
|
||||
fi
|
||||
|
||||
if [[ $iface_name == "" ]]; then
|
||||
iface_name="usb0";
|
||||
else
|
||||
extra_args+=(--iface-name "${iface_name}")
|
||||
fi
|
||||
|
||||
CONFIGFS_HOME=${FAKE_CONFIGFS} ${SUT} "${extra_args[@]}" stop
|
||||
|
||||
if test -d "${FAKE_GADGETFS}/${gadget_dir}"; then
|
||||
test_fail "Gadget was not removed!"
|
||||
fi
|
||||
}
|
||||
|
||||
test_gadget_creation_no_macs() {
|
||||
local gadget_dir="g1";
|
||||
local product_name="Souvenier BMC"
|
||||
local product_id="0xcafe"
|
||||
local bind_device="f80002000.udc"
|
||||
CONFIGFS_HOME=${FAKE_CONFIGFS} ${SUT} --product-id "${product_id}" \
|
||||
--product-name "${product_name}" \
|
||||
--bind-device "${bind_device}"
|
||||
|
||||
if test $? -ne 0; then
|
||||
test_fail "${SUT} failed"
|
||||
fi
|
||||
|
||||
if ! test -d "${FAKE_GADGETFS}/${gadget_dir}"; then
|
||||
test_fail "Gadget was not created!"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idVendor" "0x18d1"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idProduct" "${product_id}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/manufacturer" "Google"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/product" "${product_name}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/MaxPower" "100"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/strings/0x409/configuration" "EEM"
|
||||
|
||||
if [[ -e ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0/dev_addr ]]; then
|
||||
test_fail "dev_addr should not be set"
|
||||
fi
|
||||
|
||||
if [[ -e ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0/host_addr ]]; then
|
||||
test_fail "host_addr should not be set"
|
||||
fi
|
||||
|
||||
local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/eem.usb0"
|
||||
if [[ ! -L ${func_link} ]]; then
|
||||
test_fail "Symlink to the function was not created in the config"
|
||||
fi
|
||||
|
||||
local link_dest
|
||||
link_dest="$(realpath "${func_link}")"
|
||||
if [[ $link_dest != ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.usb0 ]]; then
|
||||
test_fail "Symlink points to the wrong file/dir"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/UDC" "${bind_device}"
|
||||
}
|
||||
|
||||
test_gadget_creation_alt_iface() {
|
||||
local gadget_dir="g1";
|
||||
local product_name="Souvenier BMC"
|
||||
local product_id="0xcafe"
|
||||
local bind_device="f80002000.udc"
|
||||
local iface_name="iface0"
|
||||
if ! CONFIGFS_HOME=${FAKE_CONFIGFS} ${SUT} --product-id "${product_id}" \
|
||||
--product-name "${product_name}" \
|
||||
--bind-device "${bind_device}" \
|
||||
--iface-name "${iface_name}"; then
|
||||
test_fail "${SUT} failed"
|
||||
fi
|
||||
|
||||
if [[ ! -d "${FAKE_GADGETFS}/${gadget_dir}" ]]; then
|
||||
test_fail "Gadget was not created!"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idVendor" "0x18d1"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/idProduct" "${product_id}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/manufacturer" "Google"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/strings/0x409/product" "${product_name}"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/MaxPower" "100"
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/strings/0x409/configuration" "EEM"
|
||||
|
||||
if [[ ! -d ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.${iface_name} ]]; then
|
||||
test_fail "Function directory was not created"
|
||||
fi
|
||||
|
||||
if [[ -e ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.${iface_name}/dev_addr ]]; then
|
||||
test_fail "dev_addr should not be set"
|
||||
fi
|
||||
|
||||
if [[ -e ${FAKE_GADGETFS}/${gadget_dir}/functions/eem.${iface_name}/host_addr ]]; then
|
||||
test_fail "host_addr should not be set"
|
||||
fi
|
||||
|
||||
local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/eem.${iface_name}"
|
||||
if [[ ! -L ${func_link} ]]; then
|
||||
test_fail "Symlink to the function was not created in the config"
|
||||
fi
|
||||
|
||||
local link_dest
|
||||
link_dest="$(realpath "${func_link}")"
|
||||
if [[ $link_dest != "${FAKE_GADGETFS}/${gadget_dir}/functions/eem.${iface_name}" ]]; then
|
||||
test_fail "Symlink points to the wrong file/dir"
|
||||
fi
|
||||
|
||||
check_file_content "${FAKE_GADGETFS}/${gadget_dir}/UDC" "${bind_device}"
|
||||
}
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Device Creation"
|
||||
|
||||
test_gadget_creation_with_defaults
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Device Creation With Override"
|
||||
|
||||
test_gadget_creation_with_override
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Test Device Stop"
|
||||
|
||||
test_gadget_creation_with_defaults
|
||||
test_gadget_stopping
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Device Creation/Stopping, Alternative Name"
|
||||
|
||||
test_gadget_creation_with_defaults "gAlt"
|
||||
test_gadget_stopping "gAlt"
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Device Creation without MAC Addrs"
|
||||
|
||||
test_gadget_creation_no_macs
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
test_setup "Device Creation/Stopping, Alternative Interface"
|
||||
|
||||
test_gadget_creation_alt_iface
|
||||
|
||||
test_teardown
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
echo "SUCCESS!"
|
||||
@@ -0,0 +1,57 @@
|
||||
SUMMARY = "Google USB EEM Gadget Configuration Script"
|
||||
DESCRIPTION = "Google USB EEM Gadget Configuration Script"
|
||||
PR = "r1"
|
||||
PV = "0.2"
|
||||
|
||||
LICENSE = "Apache-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
|
||||
|
||||
FILESEXTRAPATHS:prepend = "${THISDIR}/${PN}:"
|
||||
|
||||
inherit systemd
|
||||
|
||||
DEPENDS += "m4-native"
|
||||
DEPENDS += "systemd"
|
||||
RDEPENDS:${PN} += "bash"
|
||||
|
||||
BMC_USB_ECM_PRODUCT_ID ??= ""
|
||||
BMC_USB_ECM_PRODUCT_NAME ??= "${MACHINE} BMC"
|
||||
BMC_USB_ECM_HOST_MAC ??= "invalid"
|
||||
BMC_USB_ECM_DEV_MAC ??= "invalid"
|
||||
BMC_USB_ECM_BIND_DEV ??= ""
|
||||
BMC_USB_TYPE ??= "eem"
|
||||
BMC_USB_IFACE ??= "gusb0"
|
||||
|
||||
SRC_URI += "file://usb_network.service.m4"
|
||||
SRC_URI += "file://usb_network.sh"
|
||||
|
||||
SYSTEMD_PACKAGES = "${PN}"
|
||||
SYSTEMD_SERVICE:${PN} = "${@'usb_network.service' if d.getVar('BMC_USB_ECM_PRODUCT_ID') else ''}"
|
||||
|
||||
do_compile:append() {
|
||||
if [ -n "${BMC_USB_ECM_PRODUCT_ID}" ]; then
|
||||
test "X${BMC_USB_ECM_PRODUCT_NAME}" != "X" || bberror "Please define BMC_USB_ECM_PRODUCT_NAME"
|
||||
test "X${BMC_USB_ECM_BIND_DEV}" != "X" || bberror "Please define BMC_USB_ECM_BIND_DEV"
|
||||
|
||||
m4 \
|
||||
-DM_BMC_USB_PRODUCT_ID="${BMC_USB_ECM_PRODUCT_ID}" \
|
||||
-DM_BMC_USB_PRODUCT_NAME="${BMC_USB_ECM_PRODUCT_NAME}" \
|
||||
-DM_BMC_USB_TYPE="${BMC_USB_TYPE}" \
|
||||
-DM_BMC_USB_HOST_MAC="${BMC_USB_ECM_HOST_MAC}" \
|
||||
-DM_BMC_USB_DEV_MAC="${BMC_USB_ECM_DEV_MAC}" \
|
||||
-DM_BMC_USB_IFACE="${BMC_USB_IFACE}" \
|
||||
-DM_BMC_USB_BIND_DEV="${BMC_USB_ECM_BIND_DEV}" \
|
||||
-DM_SCRIPT_INSTALL_DIR="${bindir}" \
|
||||
${WORKDIR}/usb_network.service.m4 > ${WORKDIR}/usb_network.service
|
||||
fi
|
||||
}
|
||||
|
||||
do_install:append() {
|
||||
install -d ${D}/${bindir}
|
||||
install -m 0755 ${WORKDIR}/usb_network.sh ${D}/${bindir}
|
||||
|
||||
if [ -n "${BMC_USB_ECM_PRODUCT_ID}" ]; then
|
||||
install -d ${D}${systemd_system_unitdir}
|
||||
install -m 0644 ${WORKDIR}/usb_network.service ${D}${systemd_system_unitdir}
|
||||
fi
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user