Skip to content

Commit

Permalink
New sonic-buildimage images for Broadcom DNX ASIC family. (sonic-net#…
Browse files Browse the repository at this point in the history
…7598)

Introduce new sonic-buildimage images for Broadcom DNX ASIC family.

sonic-broadcom-dnx.bin
sonic-aboot-broadcom-dnx.swi

How I did it

NO CHANGE to existing make commands

make init; make configure PLATFORM=broadcom;  make target/sonic-aboot-broadcom.swi; make  target/sonic-broadcom.bin

The difference now is that it will result in new broadcom images for DNX asic family as well. 

sonic-broadcom.bin, sonic-broadcom-dnx.bin
sonic-aboot-broadcom.swi, sonic-aboot-broadcom-dnx.swi

Note: This PR also adds support for Broadcom SAI 5.0 (based on 1.8 SAI ) for DNX based platform + changes in platform x86_64-arista_7280cr3_32p4 bcm config files and platform_env.conf files
  • Loading branch information
judyjoseph authored Jun 22, 2021
1 parent 8b3fabe commit 3ad830e
Show file tree
Hide file tree
Showing 40 changed files with 577 additions and 47 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@
[submodule "src/wpasupplicant/sonic-wpa-supplicant"]
path = src/wpasupplicant/sonic-wpa-supplicant
url = https://github.com/Azure/sonic-wpa-supplicant.git
[submodule "platform/broadcom/saibcm-modules-dnx"]
path = platform/broadcom/saibcm-modules-dnx
url = https://github.com/Azure/saibcm-modules.git
branch = sdk-6.5.22-gpl-dnx
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,10 @@ tdma_timeout_usec.BCM8869X=1000000
tslam_timeout_usec.BCM8869X=1000000

appl_enable_intr_init.BCM8869X=1
polled_irq_mode.BCM8869X=1
polled_irq_mode.BCM8869X=0
polled_irq_delay.BCM8869X=1000

bcm_stat_interval.BCM8869X=1000
bcm_stat_interval.BCM8869X=1000000

mem_cache_enable_ecc.BCM8869X=1
mem_cache_enable_parity.BCM8869X=1
Expand Down Expand Up @@ -750,7 +750,8 @@ ucode_port_38=CGE23:core_1.38
ucode_port_39=CGE20:core_1.39
ucode_port_40=CGE21:core_1.40

rif_id_max=0x4000
rif_id_max=0x6000
dpp_db_path=/usr/share/bcm/db

dma_desc_aggregator_chain_length_max.BCM8869X=1000
dma_desc_aggregator_buff_size_kb.BCM8869X=100
Expand Down
1 change: 1 addition & 0 deletions device/arista/x86_64-arista_7280cr3_32p4/platform_env.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
usemsi=1
18 changes: 16 additions & 2 deletions files/build_templates/sonic_debian_extension.j2
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/sonic-ztp_*.deb || \
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
{% endif %}

{% for machine_debs in lazy_build_installer_debs.strip().split() -%}
{% set machine, pkgname = machine_debs.split('|') %}
if [[ -z "{{machine}}" || -n "{{machine}}" && $TARGET_MACHINE == "{{machine}}" ]]; then
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/{{pkgname}} || \
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
fi
{% endfor %}

# Install SONiC Device Data (and its dependencies via 'apt-get -y install -f')
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/sonic-device-data_*.deb || \
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
Expand Down Expand Up @@ -653,10 +661,11 @@ sudo mount --bind target $FILESYSTEM_ROOT/target
sudo chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS info

{% for docker_installation_target in installer_images.strip().split() -%}
{% set pkgname, docker_build_path, image = docker_installation_target.split('|') %}
{% set pkgname, docker_build_path, machine, image = docker_installation_target.split('|') %}
{% set imagefilepath = image.split(':')|first -%}
{% set imagefilename = imagefilepath.split('/')|last -%}
{% set imagename = imagefilename.split('.')|first -%}
if [[ -z "{{machine}}" || -n "{{machine}}" && $TARGET_MACHINE == "{{machine}}" ]]; then
sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS load -i {{imagefilepath}}
sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS tag {{imagename}}:latest {{imagename}}:"${SONIC_IMAGE_VERSION}"
# Check if manifest exists for {{imagename}} and it is a valid JSON
Expand All @@ -671,6 +680,7 @@ jq -e . /tmp/manifest.json || {
sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS tag {{imagename}}:latest {{imagebasename}}:"${SONIC_IMAGE_VERSION}"
sudo LANG=C chroot $FILESYSTEM_ROOT docker $SONIC_NATIVE_DOCKERD_FOR_DOCKERFS tag {{imagename}}:latest {{imagebasename}}:latest
{% endif %}
fi
{% endfor %}

SONIC_PACKAGE_MANAGER_FOLDER="/var/lib/sonic-package-manager/"
Expand Down Expand Up @@ -714,7 +724,11 @@ sudo bash -c "echo { > $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ctr_image_name
sudo bash -c "echo } >> $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ctr_image_names.json"

{% for script in installer_start_scripts.split(' ') -%}
sudo cp {{script}} $FILESYSTEM_ROOT/usr/bin/
if [ -f $TARGET_MACHINE"_{{script}}" ]; then
sudo cp $TARGET_MACHINE"_{{script}}" $FILESYSTEM_ROOT/usr/bin/{{script}}
else
sudo cp {{script}} $FILESYSTEM_ROOT/usr/bin/
fi
{% endfor %}
{% for service in installer_services.split(' ') -%}
if [ -f {{service}} ]; then
Expand Down
3 changes: 3 additions & 0 deletions onie-image-arm64.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

ONIEIMAGE_VERSION=r0

## Filesystem root
FILESYSTEM_ROOT=./fsroot-${TARGET_MACHINE}

## Filename for squashfs file system
FILESYSTEM_SQUASHFS=fs.squashfs

Expand Down
3 changes: 3 additions & 0 deletions onie-image-armhf.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

ONIEIMAGE_VERSION=r0

## Filesystem root
FILESYSTEM_ROOT=./fsroot-${TARGET_MACHINE}

## Filename for squashfs file system
FILESYSTEM_SQUASHFS=fs.squashfs

Expand Down
3 changes: 3 additions & 0 deletions onie-image.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

ONIEIMAGE_VERSION=r0

## Filesystem root
FILESYSTEM_ROOT=./fsroot-${TARGET_MACHINE}

## Filename for squashfs file system
FILESYSTEM_SQUASHFS=fs.squashfs

Expand Down
7 changes: 4 additions & 3 deletions onie-mk-demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ fi
}

[ -r "$platform_conf" ] || {
echo "Error: Unable to read installer platform configuration file: $platform_conf"
exit 1
echo "Warning: Unable to read installer platform configuration file: $platform_conf"
}

[ $# -gt 0 ] || {
Expand Down Expand Up @@ -98,7 +97,9 @@ sed -i -e "s/%%DEMO_TYPE%%/$demo_type/g" \
echo -n "."
cp -r $* $tmp_installdir || clean_up 1
echo -n "."
cp $platform_conf $tmp_installdir || clean_up 1
[ -r "$platform_conf" ] && {
cp $platform_conf $tmp_installdir || clean_up 1
}
echo "machine=$machine" > $tmp_installdir/machine.conf
echo "platform=$platform" >> $tmp_installdir/machine.conf
echo -n "."
Expand Down
10 changes: 10 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx-rpc.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

DPATH := $($(DOCKER_SYNCD_BRCM_DNX_RPC)_PATH)
DEP_FILES := $(SONIC_COMMON_FILES_LIST) $(PLATFORM_PATH)/docker-syncd-brcm-dnx-rpc.mk $(PLATFORM_PATH)/docker-syncd-brcm-dnx-rpc.dep
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
DEP_FILES += $(shell git ls-files $(DPATH))

$(DOCKER_SYNCD_BRCM_DNX_RPC)_CACHE_MODE := GIT_CONTENT_SHA
$(DOCKER_SYNCD_BRCM_DNX_RPC)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
$(DOCKER_SYNCD_BRCM_DNX_RPC)_DEP_FILES := $(DEP_FILES)

31 changes: 31 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx-rpc.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# docker image for brcm syncd with rpc

DOCKER_SYNCD_BRCM_DNX_RPC = docker-syncd-brcm-dnx-rpc.gz
DOCKER_SYNCD_DNX_BASE = docker-syncd-brcm-dnx.gz
$(DOCKER_SYNCD_BRCM_DNX_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-brcm-dnx-rpc
$(DOCKER_SYNCD_BRCM_DNX_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) $(PTF)
ifeq ($(INSTALL_DEBUG_TOOLS), y)
$(DOCKER_SYNCD_BRCM_DNX_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \
$(LIBSWSSCOMMON_DBG) \
$(LIBSAIMETADATA_DBG) \
$(LIBSAIREDIS_DBG)
endif
$(DOCKER_SYNCD_BRCM_DNX_RPC)_FILES += $(DSSERVE) $(BCMCMD) $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)
$(DOCKER_SYNCD_BRCM_DNX_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_DNX_BASE)
SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_BRCM_DNX_RPC)
ifeq ($(ENABLE_SYNCD_RPC),y)
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_BRCM_DNX_RPC)
endif

$(DOCKER_SYNCD_BRCM_DNX_RPC)_CONTAINER_NAME = syncd
$(DOCKER_SYNCD_BRCM_DNX_RPC)_VERSION = 1.0.0-rpc
$(DOCKER_SYNCD_BRCM_DNX_RPC)_PACKAGE_NAME = syncd-dnx
$(DOCKER_SYNCD_BRCM_DNX_RPC)_RUN_OPT += --privileged -t
$(DOCKER_SYNCD_BRCM_DNX_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SYNCD_BRCM_DNX_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot
$(DOCKER_SYNCD_BRCM_DNX_RPC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd
$(DOCKER_SYNCD_BRCM_DNX_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro

$(DOCKER_SYNCD_BRCM_DNX_RPC)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd
$(DOCKER_SYNCD_BRCM_DNX_RPC)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh
$(DOCKER_SYNCD_BRCM_DNX_RPC)_MACHINE = broadcom-dnx
57 changes: 57 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx-rpc/Dockerfile.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
FROM docker-syncd-brcm-dnx

## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive

COPY \
{% for deb in docker_syncd_brcm_dnx_rpc_debs.split(' ') -%}
debs/{{ deb }}{{' '}}
{%- endfor -%}
debs/

RUN apt-get purge -y syncd

## Pre-install the fundamental packages
RUN apt-get update \
&& apt-get -y install \
net-tools \
python-pip \
python-setuptools \
build-essential \
libssl-dev \
libffi-dev \
python-dev \
wget \
cmake \
libqt5core5a \
libqt5network5 \
libboost-atomic1.71.0

RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } ; \
{% for deb in docker_syncd_brcm_dnx_rpc_debs.split(' ') -%}
dpkg_apt debs/{{ deb }}{{'; '}}
{%- endfor %}

RUN wget https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz \
&& tar xvfz 1.0.0.tar.gz \
&& cd nanomsg-1.0.0 \
&& mkdir -p build \
&& cmake . \
&& make install \
&& ldconfig \
&& cd .. \
&& rm -fr nanomsg-1.0.0 \
&& rm -f 1.0.0.tar.gz \
&& pip2 install cffi==1.7.0 \
&& pip2 install --upgrade cffi==1.7.0 \
&& pip2 install wheel \
&& pip2 install nnpy \
&& mkdir -p /opt \
&& cd /opt \
&& wget https://raw.githubusercontent.com/p4lang/ptf/master/ptf_nn/ptf_nn_agent.py \
&& apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y \
&& rm -rf /root/deps

COPY ["ptf_nn_agent.conf", "/etc/supervisor/conf.d/"]

ENTRYPOINT ["/usr/local/bin/supervisord"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

docker exec -i syncd bcmcmd "$@"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

docker exec -it syncd bcmsh "$@"
10 changes: 10 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx-rpc/ptf_nn_agent.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[program:ptf_nn_agent]
command=/usr/bin/python /opt/ptf_nn_agent.py --device-socket 1@tcp://0.0.0.0:10900 -i 1-3@Ethernet12 --set-iface-rcv-buffer=109430400
process_name=ptf_nn_agent
stdout_logfile=/tmp/ptf_nn_agent.out.log
stderr_logfile=/tmp/ptf_nn_agent.err.log
redirect_stderr=false
autostart=true
autorestart=true
startsecs=1
numprocs=1
13 changes: 13 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#DPKG FRK
DOCKER_SYNCD_DNX_BASE = docker-syncd-brcm-dnx.gz
DOCKER_SYNCD_DNX_BASE_DBG = docker-syncd-brcm-dnx-$(DBG_IMAGE_MARK).gz
DPATH := $($(DOCKER_SYNCD_DNX_BASE)_PATH)
DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/broadcom/docker-syncd-brcm-dnx.mk platform/broadcom/docker-syncd-brcm-dnx.dep platform/broadcom/sai.mk
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
DEP_FILES += $(shell git ls-files $(DPATH))

$(DOCKER_SYNCD_DNX_BASE)_CACHE_MODE := GIT_CONTENT_SHA
$(DOCKER_SYNCD_DNX_BASE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
$(DOCKER_SYNCD_DNX_BASE)_DEP_FILES := $(DEP_FILES)

$(eval $(call add_dbg_docker,$(DOCKER_SYNCD_DNX_BASE),$(DOCKER_SYNCD_DNX_BASE_DBG)))
49 changes: 49 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# docker image for brcm-dnx syncd

DOCKER_SYNCD_DNX_BASE = docker-syncd-brcm-dnx.gz
DOCKER_SYNCD_DNX_BASE_DBG = docker-syncd-brcm-dnx-$(DBG_IMAGE_MARK).gz
DOCKER_SYNCD_DNX_PLATFORM_CODE = brcm-dnx

$(DOCKER_SYNCD_DNX_BASE)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_DNX_PLATFORM_CODE)
$(DOCKER_SYNCD_DNX_BASE)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)

$(DOCKER_SYNCD_DNX_BASE)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BUSTER)
$(DOCKER_SYNCD_DNX_BASE)_DBG_DEPENDS += $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_DEPENDS)
$(DOCKER_SYNCD_DNX_BASE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_IMAGE_PACKAGES)

SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_DNX_BASE)
ifneq ($(ENABLE_SYNCD_RPC),y)
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_DNX_BASE)
endif

SONIC_DOCKER_DBG_IMAGES += $(DOCKER_SYNCD_DNX_BASE_DBG)
ifneq ($(ENABLE_SYNCD_RPC),y)
SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_SYNCD_DNX_BASE_DBG)
endif


$(DOCKER_SYNCD_DNX_BASE)_DEPENDS += $(SYNCD)
$(DOCKER_SYNCD_DNX_BASE)_DEPENDS += $(BRCM_DNX_SAI)
$(DOCKER_SYNCD_DNX_BASE)_FILES += $(DSSERVE) $(BCMCMD)

ifeq ($(INSTALL_DEBUG_TOOLS), y)
$(DOCKER_SYNCD_DNX_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \
$(LIBSWSSCOMMON_DBG) \
$(LIBSAIMETADATA_DBG) \
$(LIBSAIREDIS_DBG)
endif

$(DOCKER_SYNCD_DNX_BASE)_VERSION = 1.0.0
$(DOCKER_SYNCD_DNX_BASE)_PACKAGE_NAME = syncd-dnx
$(DOCKER_SYNCD_DNX_BASE)_MACHINE = broadcom-dnx
$(DOCKER_SYNCD_DNX_BASE)_AFTER = $(DOCKER_SYNCD_BASE)
$(DOCKER_SYNCD_DNX_BASE)_CONTAINER_NAME = syncd
$(DOCKER_SYNCD_DNX_BASE)_RUN_OPT += --privileged -t
$(DOCKER_SYNCD_DNX_BASE)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SYNCD_DNX_BASE)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
$(DOCKER_SYNCD_DNX_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot

$(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd
$(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh
$(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += bcm_common:/usr/bin/bcm_common
$(DOCKER_SYNCD_DNX_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d
39 changes: 39 additions & 0 deletions platform/broadcom/docker-syncd-brcm-dnx/Dockerfile.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{% from "dockers/dockerfile-macros.j2" import install_debian_packages %}
FROM docker-config-engine-buster

ARG docker_container_name

RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf

## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update

COPY \
{% for deb in docker_syncd_brcm_dnx_debs.split(' ') -%}
debs/{{ deb }}{{' '}}
{%- endfor -%}
debs/

# Install locally-built Debian packages and implicitly install their dependencies
{{ install_debian_packages(docker_syncd_brcm_dnx_debs.split(' ')) }}

## TODO: add kmod into Depends
RUN apt-get install -yf kmod

## BRCM uses ethtool to set host interface speed
RUN apt-get install -y ethtool

COPY ["files/dsserve", "files/bcmcmd", "start.sh", "start_led.sh", "bcmsh", "/usr/bin/"]
RUN chmod +x /usr/bin/dsserve /usr/bin/bcmcmd

COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["files/supervisor-proc-exit-listener", "/usr/bin"]
COPY ["critical_processes", "/etc/supervisor/"]

## Clean up
RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y
RUN rm -rf /debs

ENTRYPOINT ["/usr/local/bin/supervisord"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash

function help()
{
echo "Usage: $0 -n [0 to $(($NUM_ASIC-1))]" 1>&2; exit 1;

}


DEV=""

PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform`

# Parse the device specific asic conf file, if it exists

ASIC_CONF=/usr/share/sonic/device/$PLATFORM/asic.conf
if [ -f "$ASIC_CONF" ]; then
source $ASIC_CONF
fi


if [[ ($NUM_ASIC -gt 1) ]]; then
OPTIND=1

while getopts ":n:h:" opt; do
case "${opt}" in
h) help
exit 0
;;
n) DEV=${OPTARG}
[ $DEV -lt $NUM_ASIC -a $DEV -ge 0 ] || help
;;
esac
done
shift "$((OPTIND-1))"

if [ -z "${DEV}" ]; then
help
fi
fi
Loading

0 comments on commit 3ad830e

Please sign in to comment.