From 9634273c63db46417e5b0a6a0a2570a7cd6266ce Mon Sep 17 00:00:00 2001 From: Maksym Sloyko Date: Tue, 3 Aug 2021 21:54:28 +0000 Subject: meta-google: Add google-usb-network recipe Add recipe for bringing up USB ECM network devices. The recipe generates * network configuration file for the interface; * systemd service that starts(stops) the USB Gadget The ECM gadget, as well as the network interface are expected to be fully configured in the bbappend file. Signed-off-by: Maksym Sloyko Change-Id: Ibb57584ce2bfd838e650eae7a4d3935c9580e502 --- .../google-usb-network/00-bmc-usb0.network.m4 | 7 + .../google-usb-network/usb_network.service.m4 | 28 ++ .../networking/google-usb-network/usb_network.sh | 165 ++++++++++++ .../google-usb-network/usb_network_test.sh | 295 +++++++++++++++++++++ .../networking/google-usb-network_git.bb | 64 +++++ 5 files changed, 559 insertions(+) create mode 100644 meta-google/recipes-google/networking/google-usb-network/00-bmc-usb0.network.m4 create mode 100644 meta-google/recipes-google/networking/google-usb-network/usb_network.service.m4 create mode 100755 meta-google/recipes-google/networking/google-usb-network/usb_network.sh create mode 100755 meta-google/recipes-google/networking/google-usb-network/usb_network_test.sh create mode 100644 meta-google/recipes-google/networking/google-usb-network_git.bb diff --git a/meta-google/recipes-google/networking/google-usb-network/00-bmc-usb0.network.m4 b/meta-google/recipes-google/networking/google-usb-network/00-bmc-usb0.network.m4 new file mode 100644 index 000000000..699ee8538 --- /dev/null +++ b/meta-google/recipes-google/networking/google-usb-network/00-bmc-usb0.network.m4 @@ -0,0 +1,7 @@ +[Match] +Name=usb0 +[Address] +Address=M_BMC_IP_ADDR +[Network] +LinkLocalAddressing=ipv6 +IPv6AcceptRA=no diff --git a/meta-google/recipes-google/networking/google-usb-network/usb_network.service.m4 b/meta-google/recipes-google/networking/google-usb-network/usb_network.service.m4 new file mode 100644 index 000000000..581c29b66 --- /dev/null +++ b/meta-google/recipes-google/networking/google-usb-network/usb_network.service.m4 @@ -0,0 +1,28 @@ +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 ECM Gadget +After=phosphor-ipmi-host.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=M_SCRIPT_INSTALL_DIR/usb_network.sh \ + --product-id "M_BMC_USB_ECM_PRODUCT_ID" \ + --product-name "M_BMC_USB_ECM_PRODUCT_NAME" \ + HOST_MAC_ARG(M_BMC_USB_ECM_HOST_MAC) \ + DEV_MAC_ARG(M_BMC_USB_ECM_DEV_MAC) \ + --bind-device "M_BMC_USB_ECM_BIND_DEV" +ExecStop=M_SCRIPT_INSTALL_DIR/usb_network.sh stop + +[Install] +WantedBy=multi-user.target diff --git a/meta-google/recipes-google/networking/google-usb-network/usb_network.sh b/meta-google/recipes-google/networking/google-usb-network/usb_network.sh new file mode 100755 index 000000000..08f9ad23b --- /dev/null +++ b/meta-google/recipes-google/networking/google-usb-network/usb_network.sh @@ -0,0 +1,165 @@ +#!/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:" + "gadget-dir-name:" + "iface-name:" +) + +print_usage() { + cat < "${gadget_dir}/idVendor" + echo ${ID_PRODUCT} > "${gadget_dir}/idProduct" + + local str_en_dir="${gadget_dir}/strings/0x409" + mkdir -p "${str_en_dir}" + echo ${STR_EN_VENDOR} > "${str_en_dir}/manufacturer" + echo ${STR_EN_PRODUCT} > "${str_en_dir}/product" + + local config_dir="${gadget_dir}/configs/c.1" + mkdir -p "${config_dir}" + echo 100 > "${config_dir}/MaxPower" + mkdir -p "${config_dir}/strings/0x409" + echo "ECM" > "${config_dir}/strings/0x409/configuration" + + local func_dir="${gadget_dir}/functions/ecm.${IFACE_NAME}" + mkdir -p "${func_dir}" + + if [[ -n $HOST_MAC_ADDR ]]; then + echo ${HOST_MAC_ADDR} > ${func_dir}/host_addr + fi + + if [[ -n $DEV_MAC_ADDR ]]; then + echo ${DEV_MAC_ADDR} > ${func_dir}/dev_addr + fi + + ln -s "${func_dir}" "${config_dir}" + + echo "${BIND_DEVICE}" > ${gadget_dir}/UDC +} + +gadget_stop() { + local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}" + rm -f ${gadget_dir}/configs/c.1/ecm.${IFACE_NAME} + rm -rf ${gadget_dir}/configs/c.1/strings/0x409 + rm -rf ${gadget_dir}/configs/c.1 + rm -rf ${gadget_dir}/strings/0x409 + rm -rf ${gadget_dir}/functions/ecm.${IFACE_NAME} + rm -rf ${gadget_dir} +} + +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="" +HOST_MAC_ADDR="" +BIND_DEVICE="" +ACTION="start" +GADGET_DIR_NAME="g1" +IFACE_NAME="usb0" +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 + ;; + --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 [[ $ACTION == "stop" ]]; then + gadget_stop +else + gadget_start +fi diff --git a/meta-google/recipes-google/networking/google-usb-network/usb_network_test.sh b/meta-google/recipes-google/networking/google-usb-network/usb_network_test.sh new file mode 100755 index 000000000..e5894338b --- /dev/null +++ b/meta-google/recipes-google/networking/google-usb-network/usb_network_test.sh @@ -0,0 +1,295 @@ +#!/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="" +TEMPFILES="" +# Script under test +SUT=$PWD/usb_network.sh + +TEST_STATUS="OK" + +test_setup() { + echo -n "Testing $1 ..." + FAKE_CONFIGFS=$(mktemp -d) + TEMPDIRS="${TEMPDIRS} ${FAKE_CONFIGFS}" + FAKE_GADGETFS=$FAKE_CONFIGFS/usb_gadget + mkdir -p "$FAKE_GADGETFS" +} + +test_teardown() { + echo ${TEST_STATUS} + if test -n "$TEMPDIRS"; then + rm -rf ${TEMPDIRS} + fi + if test -n "$TEMPFILES"; then + rm -f $TEMPFILES + fi +} + +test_fail() { + echo -n " $@ " >&2 + TEST_STATUS="FAIL" + + test_teardown + exit 1 +} + +check_file_content() { + local filename="$1" + local expected_content="$2" + + if ! test -f "${filename}"; then + test_fail "File ${filename} does not exist!" + fi + + local actual_content=$(cat ${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=(${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" + 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[@]} + + 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 "ECM" + check_file_content ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.usb0/dev_addr "${dev_mac}" + check_file_content ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.usb0/host_addr "${host_mac}" + + if ! test -d ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.usb0; then + test_fail "Function directory was not created" + fi + + local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/ecm.usb0" + if ! test -L "${func_link}"; then + test_fail "Symlink to the function was not created in the config" + fi + + local link_dest=$(realpath ${func_link}) + if [[ $link_dest != ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.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=(${extra_args} --gadget-dir-name "${gadget_dir}") + fi + + if [[ $iface_name == "" ]]; then + iface_name="usb0"; + else + extra_args=(${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 "ECM" + + if test -e ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.usb0/dev_addr; then + test_fail "dev_addr should not be set" + fi + + if test -e ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.usb0/host_addr; then + test_fail "host_addr should not be set" + fi + + local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/ecm.usb0" + if ! test -L "${func_link}"; then + test_fail "Symlink to the function was not created in the config" + fi + + local link_dest=$(realpath ${func_link}) + if [[ $link_dest != ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.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" + CONFIGFS_HOME=${FAKE_CONFIGFS} ${SUT} --product-id "${product_id}" \ + --product-name "${product_name}" \ + --bind-device "${bind_device}" \ + --iface-name "${iface_name}" + + 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 "ECM" + + if ! test -d ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.${iface_name}; then + test_fail "Function directory was not created" + fi + + if test -e ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.${iface_name}/dev_addr; then + test_fail "dev_addr should not be set" + fi + + if test -e ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.${iface_name}/host_addr; then + test_fail "host_addr should not be set" + fi + + local func_link="${FAKE_GADGETFS}/${gadget_dir}/configs/c.1/ecm.${iface_name}" + if ! test -L "${func_link}"; then + test_fail "Symlink to the function was not created in the config" + fi + + local link_dest=$(realpath ${func_link}) + if [[ $link_dest != ${FAKE_GADGETFS}/${gadget_dir}/functions/ecm.${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!" diff --git a/meta-google/recipes-google/networking/google-usb-network_git.bb b/meta-google/recipes-google/networking/google-usb-network_git.bb new file mode 100644 index 000000000..ec51eaa5b --- /dev/null +++ b/meta-google/recipes-google/networking/google-usb-network_git.bb @@ -0,0 +1,64 @@ +SUMMARY = "Google USB ECM Gadget Configuration Script" +DESCRIPTION = "Google USB ECM 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" + +SYSTEMD_PACKAGES = "${PN}" +SYSTEMD_SERVICE_${PN} = "usb_network.service" + +BMC_IP_ADDR ??= "169.254.95.118/16" +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_CONFIG_PRIORITY ??= "" +BMC_USB_CONFIG_FILENAME ??= "${BMC_USB_CONFIG_PRIORITY}-bmc-usb0.network" + +SRC_URI += "file://00-bmc-usb0.network.m4" +SRC_URI += "file://usb_network.service.m4" +SRC_URI += "file://usb_network.sh" + +FILES_${PN} = "${bindir}/usb_network.sh" +FILES_${PN}_append = " ${systemd_unitdir}/network/${BMC_USB_CONFIG_FILENAME}" + +do_compile() { + test "X${BMC_IP_ADDR}" != "X" || bberror "Please define BMC_IP_ADDR" + m4 -DM_BMC_IP_ADDR=${BMC_IP_ADDR} ${WORKDIR}/00-bmc-usb0.network.m4 > ${S}/00-bmc-usb0.network + + test "X${BMC_USB_ECM_PRODUCT_ID}" != "X" || bberror "Please define BMC_USB_ECM_PRODUCT_ID" + 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_ECM_PRODUCT_ID="${BMC_USB_ECM_PRODUCT_ID}" \ + -DM_BMC_USB_ECM_PRODUCT_NAME="${BMC_USB_ECM_PRODUCT_NAME}" \ + -DM_BMC_USB_ECM_HOST_MAC="${BMC_USB_ECM_HOST_MAC}" \ + -DM_BMC_USB_ECM_DEV_MAC="${BMC_USB_ECM_DEV_MAC}" \ + -DM_BMC_USB_ECM_BIND_DEV="${BMC_USB_ECM_BIND_DEV}" \ + -DM_SCRIPT_INSTALL_DIR="${bindir}" \ + ${WORKDIR}/usb_network.service.m4 > ${S}/usb_network.service +} + +do_install() { + install -d ${D}/${bindir} + install -m 0755 ${WORKDIR}/usb_network.sh ${D}/${bindir} + + install -d ${D}${systemd_system_unitdir} + install -m 0644 ${S}/usb_network.service ${D}${systemd_system_unitdir} + + install -d ${D}${systemd_unitdir}/network + install -m 0644 ${S}/00-bmc-usb0.network \ + ${D}${systemd_unitdir}/network/${BMC_USB_CONFIG_FILENAME} +} -- cgit v1.2.3