From 85689edcbf2de6371e33d402c135715e4b671554 Mon Sep 17 00:00:00 2001 From: Bill Schwartz Date: Mon, 18 Nov 2019 11:55:37 -0500 Subject: [PATCH 1/5] Initial commit for introducing the SONiC Platform Development Environment (PDE) into sonic-buildimage --- Makefile.work | 20 +- dockers/docker-pde/Dockerfile | 54 ++ dockers/docker-pde/Dockerfile.j2 | 72 ++ .../base_image_files/pde-test-harness | 63 ++ .../base_image_files/port_breakout.py | 833 ++++++++++++++++++ dockers/docker-pde/docker_init.sh | 31 + dockers/docker-pde/supervisord.conf | 12 + files/build_templates/docker_image_ctl.j2 | 5 +- files/build_templates/pde.service.j2 | 22 + platform/broadcom/one-pde-image.mk | 45 + rules/config | 3 + rules/docker-pde.mk | 46 + rules/sonic-pde-tests.mk | 17 + slave.mk | 5 + 14 files changed, 1226 insertions(+), 2 deletions(-) create mode 100644 dockers/docker-pde/Dockerfile create mode 100644 dockers/docker-pde/Dockerfile.j2 create mode 100755 dockers/docker-pde/base_image_files/pde-test-harness create mode 100755 dockers/docker-pde/base_image_files/port_breakout.py create mode 100755 dockers/docker-pde/docker_init.sh create mode 100644 dockers/docker-pde/supervisord.conf create mode 100644 files/build_templates/pde.service.j2 create mode 100644 platform/broadcom/one-pde-image.mk create mode 100644 rules/docker-pde.mk create mode 100644 rules/sonic-pde-tests.mk diff --git a/Makefile.work b/Makefile.work index 37ee2e11529d..808fa1d17fbb 100644 --- a/Makefile.work +++ b/Makefile.work @@ -7,6 +7,7 @@ # * BUILD_NUMBER: Desired version-number to pass to the building-system. # * ENABLE_DHCP_GRAPH_SERVICE: Enables get-graph service to fetch minigraph files # through http. +# * ENABLE_PDE: Enables platform development environment. # * SHUTDOWN_BGP_ON_START: Sets admin-down state for all bgp peerings after restart. # * ENABLE_PFCWD_ON_START: Enable PFC Watchdog (PFCWD) on server-facing ports # * by default for TOR switch. @@ -162,6 +163,7 @@ SONIC_BUILD_INSTRUCTION := make \ BUILD_NUMBER=$(BUILD_NUMBER) \ BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \ ENABLE_DHCP_GRAPH_SERVICE=$(ENABLE_DHCP_GRAPH_SERVICE) \ + ENABLE_PDE=$(ENABLE_PDE) \ SHUTDOWN_BGP_ON_START=$(SHUTDOWN_BGP_ON_START) \ SONIC_ENABLE_PFCWD_ON_START=$(ENABLE_PFCWD_ON_START) \ SONIC_ENABLE_SYNCD_RPC=$(ENABLE_SYNCD_RPC) \ @@ -178,7 +180,17 @@ SONIC_BUILD_INSTRUCTION := make \ EXTRA_JESSIE_TARGETS=$(EXTRA_JESSIE_TARGETS) \ $(SONIC_OVERRIDE_BUILD_VARS) -.PHONY: sonic-slave-build sonic-slave-bash init reset +PDESUBMODULES = src/sonic-linux-kernel \ + src/sonic-utilities \ + src/sonic-platform-common \ + src/sonic-swss-common \ + src/sonic-py-swsssdk \ + src/redis-dump-load \ + src/sonic-sairedis \ + src/sonic-platform-daemons \ + src/sonic-platform-pde + +.PHONY: sonic-slave-build sonic-slave-bash init initpde reset .DEFAULT_GOAL := all @@ -226,6 +238,12 @@ showtag: @echo $(SLAVE_IMAGE):$(SLAVE_TAG) @echo $(SLAVE_BASE_IMAGE):$(SLAVE_BASE_TAG) +initpde: + @for submodule in $(PDESUBMODULES) ; do \ + git submodule update --init --recursive $$submodule ; \ + done + @git submodule foreach --recursive '[ -f .git ] && echo "gitdir: $$(realpath --relative-to=. $$(cut -d" " -f2 .git))" > .git' + init : @git submodule update --init --recursive @git submodule foreach --recursive '[ -f .git ] && echo "gitdir: $$(realpath --relative-to=. $$(cut -d" " -f2 .git))" > .git' diff --git a/dockers/docker-pde/Dockerfile b/dockers/docker-pde/Dockerfile new file mode 100644 index 000000000000..46002fed9e25 --- /dev/null +++ b/dockers/docker-pde/Dockerfile @@ -0,0 +1,54 @@ + +FROM docker-config-engine-stretch + +ARG docker_container_name +ENV PYTHONPATH=/usr/share/sonic/platform + +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 + +# Update apt's cache of available packages +RUN apt-get update && apt-get install -y ipmitool telnet busybox kmod + +RUN pip install pytest pexpect + +# Copy locally-built Debian package dependencies +COPY \ +debs/libsaibcm_3.5.3.1m-25_amd64.deb debs/sonic-platform-pde_1.0_amd64.deb /debs/ + +# Install locally-built Debian packages and implicitly install their dependencies +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; \ +dpkg_apt /debs/libsaibcm_3.5.3.1m-25_amd64.deb; \ +dpkg_apt /debs/sonic-platform-pde_1.0_amd64.deb + +# Copy locally-built Debian package dependencies +COPY \ +python-debs/python-sonic-utilities_1.2-1_all.deb /debs/ + +# Install locally-built Debian packages and implicitly install their dependencies +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /debs/python-sonic-utilities_1.2-1_all.deb + +# Copy locally-built Python wheel dependencies +COPY \ +python-wheels/sonic_platform_common-1.0-py2-none-any.whl /python-wheels/ + +# Install locally-built Python wheel dependencies +RUN pip install \ +/python-wheels/sonic_platform_common-1.0-py2-none-any.whl + + + +# Clean up +RUN apt-get clean -y; \ + apt-get autoclean -y; \ + apt-get autoremove -y +RUN rm -rf /debs ~/.cache + +RUN mkdir -p /home/pde + +COPY ["base_image_files/port_breakout.py", "/usr/local/bin/"] +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["docker_init.sh", "/usr/bin/"] +ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-pde/Dockerfile.j2 b/dockers/docker-pde/Dockerfile.j2 new file mode 100644 index 000000000000..515a6d492206 --- /dev/null +++ b/dockers/docker-pde/Dockerfile.j2 @@ -0,0 +1,72 @@ +{% from "dockers/dockerfile-macros.j2" import install_debian_packages, install_python_wheels, copy_files %} +FROM docker-config-engine-stretch + +ARG docker_container_name +ENV PYTHONPATH=/usr/share/sonic/platform + +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 + +# Update apt's cache of available packages +RUN apt-get update && apt-get install -y ipmitool telnet busybox kmod + +RUN pip install pytest pexpect + +{% if docker_pde_debs.strip() -%} +# Copy locally-built Debian package dependencies +COPY \ +{% for deb in docker_pde_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +/debs/ + +# Install locally-built Debian packages and implicitly install their dependencies +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }{%- for deb in docker_pde_debs.split(' ') %}; \ +dpkg_apt /debs/{{ deb }} +{%- endfor %} +{%- endif %} + +{% if docker_pde_pydebs.strip() -%} +# Copy locally-built Debian package dependencies +COPY \ +{% for deb in docker_pde_pydebs.split(' ') -%} +python-debs/{{ deb }}{{' '}} +{%- endfor -%} +/debs/ + +# Install locally-built Debian packages and implicitly install their dependencies +{%- for deb in docker_pde_pydebs.split(' ') %} +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /debs/{{ deb }} +{%- endfor %} +{%- endif %} + +{% if docker_pde_whls.strip() -%} +# Copy locally-built Python wheel dependencies +COPY \ +{% for whl in docker_pde_whls.split(' ') -%} +python-wheels/{{ whl }}{{' '}} +{%- endfor -%} +/python-wheels/ + +# Install locally-built Python wheel dependencies +RUN pip install \ +{% for whl in docker_pde_whls.split(' ') -%} +/python-wheels/{{ whl }}{{' '}} +{%- endfor %} +{% endif %} + + +# Clean up +RUN apt-get clean -y; \ + apt-get autoclean -y; \ + apt-get autoremove -y +RUN rm -rf /debs ~/.cache + +RUN mkdir -p /home/pde + +COPY ["base_image_files/port_breakout.py", "/usr/local/bin/"] +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["docker_init.sh", "/usr/bin/"] +ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-pde/base_image_files/pde-test-harness b/dockers/docker-pde/base_image_files/pde-test-harness new file mode 100755 index 000000000000..39fdde89ba14 --- /dev/null +++ b/dockers/docker-pde/base_image_files/pde-test-harness @@ -0,0 +1,63 @@ +#!/bin/bash + +usage() +{ + echo "usage: $0 " + exit 1 +} + +if [ $# -lt 1 ] +then + usage +fi + +case $1 in +-h | help) + usage + ;; +-l | ls | list) + docker exec -it -w /usr/local/sonic_pde_tests pde ls + exit 0 + ;; +*) + ;; +esac + +# Make sure only root can run our script +if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" 1>&2 + exit 1 +fi + +# Stop swss/syncd service to ensure there is only 1 SAI instance at a time +systemctl stop swss + +if [ $(grep -c 'platform:ro' $(which pde.sh)) -gt 0 ]; then + systemctl stop pde + sleep 1 + docker rename pde pde.orig + sed -i 's#platform:ro#platform#g' $(which pde.sh) + sed -i 's#hwsku:ro#hwsku#g' $(which pde.sh) + systemctl start pde +fi + +# Allow 5 seconds for the docker-pde to be online +err=1 +for t in $(seq 5); do + if [ $(docker ps | grep -c pde) -gt 0 ]; then + err=0 + break + fi + sleep 1 +done +if [ ${err} -ne 0 ]; then + echo "docker-pde is not alive, existing ..." + exit 1 +fi + +# Now launch the PDE pytest +docker exec -it -w /usr/local/sonic_pde_tests pde pytest $* + +# Restart the swss service +systemctl start swss + diff --git a/dockers/docker-pde/base_image_files/port_breakout.py b/dockers/docker-pde/base_image_files/port_breakout.py new file mode 100755 index 000000000000..0060f0e96d28 --- /dev/null +++ b/dockers/docker-pde/base_image_files/port_breakout.py @@ -0,0 +1,833 @@ +#! /usr/bin/python -u + +import os +import sys +import re +import getopt +import copy +import json +import shutil +import os.path +import subprocess + +SIM_HOST = False + +SAI_PROFILE_DELIMITER = '=' +INTERFACE_KEY="Ethernet" +if not SIM_HOST: + NEW_FILE_EXT="" +else: + NEW_FILE_EXT="" + +sonic_platforms = { + "x86_64-accton_as9716_32d-r0": { + "breakout": { + "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "1x400", "4x100", "4x50", "2x100", "2x200", "4x25", "4x10" ] + } + }, + "x86_64-accton_as7326_56x-r0": { + "breakout": { + "48,52,56,60,64,68,72": [ "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-accton_as7712_32x-r0": { + "breakout": { + "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-accton_as7816_64x-r0": { + "breakout": { + "0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120": [ "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-accton_as7726_32x-r0": { + "breakout": { + "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120": [ "4x25", "4x10", "1x100", "1x40" ] + } + }, + "x86_64-delta_ag9032v1-r0": { + "breakout": { + "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-quanta_ix4_bwde-r0": { + "breakout": { + "128,132,136,140,144,148,152,156,192,196,200,204,208,212,216,220": [ + "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-quanta_ix8_rglbmc-r0": { + "breakout": { + "48,52,56,60,64,68,72": [ "4x10", "4x25", "1x100", "1x40" ] + } + }, + "x86_64-quanta_ix9_bwde-r0": { + "breakout": { + "0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248": [ "1x400", "4x100", "4x25", "4x10", "4x50", "2x200", "2x100" ] + } + } +} + +##################################################################################################### +### Platform related code + +if not SIM_HOST: + def get_platform(): + cmd = "cat /host/machine.conf | grep onie_platform | cut -d '=' -f 2" + pin = subprocess.Popen(cmd, + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + id = pin.communicate()[0] + id = id.strip() + return id + + def get_platform_path(): + path = "/usr/share/sonic/platform" + if os.path.exists(path): + return path + path = "/usr/share/sonic/device/" + get_platform() + return path + + def get_hwsku(): + dir = get_platform_path() + pin = subprocess.Popen("cat " + dir + "/default_sku | cut -d ' ' -f 1", + shell=True, + close_fds=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + id = pin.communicate()[0] + id = id.strip() + return id + + + # run command + def run_command(command, display_cmd=False, ignore_error=False, print_to_console=True): + ### + ### Run bash command and print output to stdout + ### + if display_cmd == True: + print("Running command: " + command) + + proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + (out, err) = proc.communicate() + + if len(out) > 0 and print_to_console: + print(out) + + if proc.returncode != 0 and not ignore_error: + sys.exit(proc.returncode) + + return out, err + + def get_bcm_file(platform, hwsku): + sai_profile_kvs = {} + + sai_file = get_platform_path() + "/" + hwsku + "/" + "sai.profile" + command = "cat "+ sai_file + sai_profile_content, _ = run_command(command, print_to_console=False) + + for line in sai_profile_content.split('\n'): + if not SAI_PROFILE_DELIMITER in line: + continue + key, value = line.split(SAI_PROFILE_DELIMITER) + sai_profile_kvs[key] = value.strip() + + try: + sai_xml_path = sai_profile_kvs['SAI_INIT_CONFIG_FILE'] + except KeyError: + print >> sys.stderr, "Failed to get SAI XML from sai profile" + sys.exit(1) + + bcm_file = "config.bcm" + if not SIM_HOST: + bcm_file = get_platform_path() + "/" + hwsku + "/" + os.path.basename(sai_xml_path) + + return bcm_file + +##################################################################################################### + + +def get_ini_file(platform, hwsku): + if not SIM_HOST: + ini_file = get_platform_path() + '/' + hwsku + '/' + "port_config.ini" + else: + ini_file = "port_config.ini" + return ini_file + +def get_cfg_file(platform, hwsku): + if not SIM_HOST: + cfg_file = "/etc/sonic/config_db.json" + else: + cfg_file = "config_db.json" + return cfg_file + +def get_led_file(platform, hwsku): + if not SIM_HOST: + led_file = get_platform_path() + "/led_proc_init.soc" + else: + led_file = "led_proc_init.soc" + return led_file + +def display_files(platform, hwsku): + print("BCM File:[%s]" % (get_bcm_file(platform, hwsku))) + print("INI File:[%s]" % (get_ini_file(platform, hwsku))) + print("CFG File:[%s]" % (get_cfg_file(platform, hwsku))) + +bko_dict_4 = { + "1x100": { "lanes":4, "speed":100, "step":4, "bko":0, "name": "hundredGigE" }, + "1x40": { "lanes":4, "speed":40, "step":4, "bko":0, "name": "fourtyGigE" }, + "4x10": { "lanes":4, "speed":10, "step":1, "bko":1, "name": "tenGigE" }, + "4x25": { "lanes":4, "speed":25, "step":1, "bko":1, "name": "twentyfiveGigE" }, +} + +bko_dict_8 = { + "1x400": { "lanes":8, "speed":400, "step":8, "bko":0, "name": "fourhundredGigE" }, + "2x200": { "lanes":8, "speed":200, "step":4, "bko":1, "name": "twohundredGigE" }, + "2x100": { "lanes":8, "speed":100, "step":4, "bko":1, "name": "hundredGigE" }, + "4x100": { "lanes":8, "speed":100, "step":2, "bko":1, "name": "hundredGigE" }, + "4x50": { "lanes":8, "speed":50, "step":2, "bko":1, "name": "fiftyGigE" }, + "4x25": { "lanes":4, "speed":25, "step":1, "bko":1, "name": "twentyfiveGigE" }, + "4x10": { "lanes":4, "speed":10, "step":1, "bko":1, "name": "tenGigE" }, +} + +bko_dict = bko_dict_4 + +# +# Get breakout step: +# +def bko_opt_valid(opt): + if opt in bko_dict: + return True + else: + return False + +def get_bkout_step(opt): + return bko_dict[opt]["step"] + +def get_bkout_subport_name(opt): + return bko_dict[opt]["name"] + +def get_bkout_subport_speed(opt): + return bko_dict[opt]["speed"] + +def get_is_bkout(opt): + return bko_dict[opt]["bko"] + +def get_bkout_lanes(opt): + return bko_dict[opt]["lanes"] + +def get_bkout_ports(port, opt): + lanes = 4 + step = 1 + + if not port.startswith(INTERFACE_KEY): + return None + + idx = port.split()[0].split(INTERFACE_KEY,1)[1] + if not idx.isdigit(): + return None + + ports = [] + for i in range(0, lanes, step): + portx = INTERFACE_KEY + str(int(idx) + (i/step)) + ports.append(portx) + return ports + + +# +# Breakout a port in INI file: +# Ethernet48 81,82,83,84 hundredGigE13 + +# Change to +# Ethernet48 81 twentyfiveGigE13:1 +# Ethernet49 82 twentyfiveGigE13:2 +# Ethernet50 83 twentyfiveGigE13:3 +# Ethernet51 84 twentyfiveGigE13:4 + +# +# Ethernet48 81,82,83,84 hundredGigE13 +# return: +# "48" +# ["81", "82", "83", "84"] +# "hundredGigE" +# "13" + + +def get_info_in_ini(line, title): + idx = line.split()[0].split(INTERFACE_KEY,1)[1] + lanes = line.split()[1].split(",") + name = line.split()[2] + temp = name.split(":")[0] + porti = re.sub('.*?([0-9]*)$',r'\1', temp) + + if "index" in title: + fp_idx = int(line.split()[title.index("index")]) + else: + fp_idx = None + return idx, lanes, name, porti, fp_idx + +def break_in_ini(port, ini_file, opt): + print("Breaking port %s to %s in ini ..." % (port, opt)) + + bak_file = ini_file + ".bak" + shutil.copy(ini_file, bak_file) + + new_file = ini_file + NEW_FILE_EXT + step = get_bkout_step(opt) + + f_in = open(bak_file, 'r') + f_out = open(new_file, 'w') + + first_port = True + title = [] + + for line in f_in.readlines(): + line.strip() + if len(line.rstrip()) == 0: + continue + + if re.search("^#", line) is not None: + # The current format is: # name lanes alias index speed + # Where the ordering of the columns can vary + if len(title) == 0: + title = line.split()[1:] + print title + f_out.write(line) + continue + + line = line.lstrip() + line_port = line.split()[0] + + if line_port in get_bkout_ports(port, opt): + oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) + + if get_is_bkout(opt) and len(olanes) < get_bkout_lanes(opt): + print("Port %s Already breakout ..." % (port)) + print("Existing ...") + f_in.close() + f_out.close() + shutil.copy(bak_file, new_file) + + sys.exit() + + # + # Non-Breakout case + # + if not get_is_bkout(opt) and not first_port: + print("--- {} removed".format(line_port)) + continue + + if not get_is_bkout(opt) and first_port: + idx = oidx + lanes = [] + for i in range(0, get_bkout_lanes(opt), 1): + lanes.append(str(int(olanes[0])+i)) + porti = oporti + + if get_is_bkout(opt): + idx = oidx + lanes = olanes + porti = oporti + + # + # original string: + # Ethernet20 69,70,71,72 hundredGigE6 + # + print(" %s" % line.rstrip()) + + # Generate new interface line + for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): + # + # Ethernet20 + # + temp_str = "Ethernet%d" % (int(idx) + (i/step)) + new_intf = "%-15s " % temp_str + + temp_str = lanes[i+0] + # + # generate 69 + # + for j in range(1, step): + temp_str += ",%s" % (lanes[i+j]) + new_intf += "%-21s " % temp_str + + # + # Generate twentyfiveGigE6:i + # + if get_is_bkout(opt): + temp_str = "%s%s:%d" % (get_bkout_subport_name(opt), porti, (i/step + 1)) + else: + temp_str = "%s%s" % (get_bkout_subport_name(opt), porti) + + new_intf += "%-19s " % temp_str + + # + # index + # + if fp_idx is not None: + temp_str = "%d" % (fp_idx) + new_intf += "%-6s " % temp_str + + + # + # speed + # + temp_str = "%d000" % get_bkout_subport_speed(opt) + new_intf += "%-10s " % temp_str + + # + # valid_speeds + # + if 'valid_speeds' in title: + temp_str = str(get_bkout_subport_speed(opt) * 1000) + if get_bkout_subport_speed(opt) == 100: + if get_bkout_step(opt) == 4: + # NRZ mode + temp_str = "100000,40000" + else: + # PAM4 mode + temp_str = "100000" + elif get_bkout_subport_speed(opt) == 40: + temp_str = "100000,40000" + + new_intf += "%s" % temp_str + + + if not get_is_bkout(opt) and first_port: + print "===>" + new_intf + new_intf += "\n" + f_out.write(new_intf) + first_port = False + if get_is_bkout(opt): + print "===>" + new_intf + new_intf += "\n" + f_out.write(new_intf) + + else: + f_out.write(line) + + print "--------------------------------------------------------" + f_in.close() + f_out.close() + + print lanes + return lanes + +# +# Parse logic port, phyical port, speed from bcm +# +def parse_port_bcm(bcm_str): + lp = bcm_str.split("=")[0].split("_")[1] + pp = bcm_str.split("=")[1].split(":")[0] + sp = bcm_str.split("=")[1].split(":")[1] + + return lp, pp, sp + +# +# portmap_84=81:100 +# +# portmap_84=81:25 +# portmap_85=82:25 +# portmap_86=83:25 +# portmap_87=84:25 +# +# +def break_in_bcm(port, lanes, bcm_file, opt, platform): + print("Breaking %s to %s in bcm ..." % (port, opt)) + + bak_file = bcm_file + ".bak" + shutil.copy(bcm_file, bak_file) + + new_file = bcm_file + NEW_FILE_EXT + step = get_bkout_step(opt) + + f_in = open(bak_file, 'r') + f_out = open(new_file, 'w') + + first_port = True + fec_removed = False + print lanes + for oline in f_in.readlines(): + line = oline.lstrip() + + if line.startswith('#'): + f_out.write(oline) + continue + + ### when running in unbreakout mode, the FEC setting per breakout should be removed + if not get_is_bkout(opt) and line.startswith("port_fec") and fec_removed: + continue + if not line.startswith("portmap"): + f_out.write(oline) + continue + + ### logic port, phyical port, speed + lp, pp, sp = parse_port_bcm(line) + if pp not in lanes: + f_out.write(oline) + fec_removed = False + continue + + if not get_is_bkout(opt): + fec_removed = True + + if not get_is_bkout(opt) and not first_port: + print("--- portmap_{} removed".format(lp)) + continue + + #### generate new port map + print(" %s" % line.rstrip()) + for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): + if '.' in lp: + nlp = lp.split('.')[0] + unit = lp.split('.')[1] + new_intf = "portmap_%d.%s=%d:%d:%d" % ((int(nlp) + (i / step)), unit, (int(pp)+i), get_bkout_subport_speed(opt), get_bkout_step(opt)) + else: + new_intf = "portmap_%d=%d:%d:%d" % ((int(lp) + (i / step)), (int(pp)+i), get_bkout_subport_speed(opt), get_bkout_step(opt)) + fec_intf = "port_fec_"+ str(int(lp) + (i/step)) +"=3" + + if not get_is_bkout(opt) and first_port: + f_out.write(new_intf) + f_out.write("\n") + print "===>" + new_intf + first_port = False + if get_is_bkout(opt): + f_out.write(new_intf) + f_out.write("\n") + ### generate default FEC only for IX9 platform + if opt == "4x100" and platform == "x86_64-quanta_ix9_bwde-r0": + f_out.write(fec_intf) + f_out.write("\n") + print "===>" + new_intf + + print "--------------------------------------------------------" + f_in.close() + f_out.close() + +# +# breakout ports in json file +# +def break_in_cfg(port, cfg_file, lanes, opt): + if not os.access(os.path.dirname(cfg_file), os.W_OK): + print("Skipping config_db.json updates for a write permission issue") + return + + step = get_bkout_step(opt) + print("Breaking %s to %s in cfg ... " % (port, opt)) + + bak_file = cfg_file + ".bak" + shutil.copy(cfg_file, bak_file) + + new_file = cfg_file + NEW_FILE_EXT + + with open(bak_file) as f: + data = json.load(f) + + with open(cfg_file, 'w') as outfile: + json.dump(data, outfile, indent=4, sort_keys=True) + + ### + ### Process in 'INTERFACE' + ### + if 'INTERFACE' in data: + for key, value in sorted(data['INTERFACE'].iteritems()): + pkey = key.split('|')[0] + if port == pkey: + data['INTERFACE'].pop(key) + + ### + ### Process in 'PORT' + + + ### remove port instance in data + ### + ports = get_bkout_ports(port, opt) + for x in ports: + if data['PORT'].get(x) != None: + port_instance = data['PORT'].get(x) + data['PORT'].pop(x) + print " ", x, port_instance + + idx = port.split()[0].split(INTERFACE_KEY,1)[1] + porti = re.sub('.*?([0-9]*)$',r'\1', port_instance['alias'].split(":")[0]) + + for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): + + if get_is_bkout(opt): + temp_str = lanes[i] + for j in range(1, step): + temp_str += ",%s" % (lanes[i+j]) + port_instance['lanes'] = temp_str + port_instance['alias'] = get_bkout_subport_name(opt) + porti + ':' + str(i/step + 1) + else: + port_instance['alias'] = get_bkout_subport_name(opt) + porti + port_instance['lanes'] = ','.join(str(e) for e in lanes) + + port_instance['speed'] = str(get_bkout_subport_speed(opt)) + "000" + port_instance['valid_speeds'] = str(get_bkout_subport_speed(opt)) + "000" + + new_port = INTERFACE_KEY + str(int(idx) + (i/step)) + xxx = copy.deepcopy(port_instance) + data['PORT'][new_port] = xxx + ### print data['PORT'][new_port] + + for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): + new_port = INTERFACE_KEY + str(int(idx) + (i/step)) + print "===>", new_port, data['PORT'][new_port] + + with open(new_file, 'w') as outfile: + json.dump(data, outfile, indent=4, sort_keys=True) + + print "--------------------------------------------------------" + +def break_a_port(port, opt, platform, hwsku): + ini_file = get_ini_file(platform, hwsku) + bcm_file = get_bcm_file(platform, hwsku) + cfg_file = get_cfg_file(platform, hwsku) + + lanes = break_in_ini(port, ini_file, opt) + break_in_bcm(port, lanes, bcm_file, opt, platform) + break_in_cfg(port, cfg_file, lanes, opt) + +def usage(): + print "Usage: " + sys.argv[0] + " interface 4x100|4x25" + print "Breakout None-breaokout a port" + print "Options:" + print " -p port" + print " -o breakout option" + for k in bko_dict: + print " %s" % k + print " " + print "Example:" + print " Breakout port Ethernet4 to 4x10G" + print " %s -p Ethernet4 -o 4x10" % (sys.argv[0]) + print " None-Breakout port Ethernet4 to 40G" + print " %s -p Ethernet4 -o 1x40" % (sys.argv[0]) + print " " + print "Note:" + print " Make sure understand which ports are able to breakout before execute command." + print " Make backup below config files" + print " - /usr/share/sonic/device/[platform]/[hwsku]/[config.bcm]" + print " - /usr/share/sonic/device/[platform]/[hwsku]/port_config.ini" + print " - /etc/sonic/config_db.json" + + sys.exit(1) + +def platform_checking(platform, hwsku, port, opt): + # + # default allow breakout ports on any platforms and ports + # + rc = True + + if not port.startswith(INTERFACE_KEY): + print "Wrong port name %s ..." % (port) + return False + + + if platform in sonic_platforms and 'breakout' in sonic_platforms[platform]: + idx = port.split()[0].split(INTERFACE_KEY,1)[1] + for keys in sonic_platforms[platform]['breakout']: + if idx in keys.split(',') and opt in sonic_platforms[platform]['breakout'][keys]: + print "Breakout port %s to %s in platform %s is allowed." % (port, opt, platform) + return True + else: + print "Error: Breakout port %s to %s in platform %s is NOT allowed !!!" % (port, opt, platform) + rc = False + + + # + # Platforms not in sonic_platforms, or not defined 'breakout' + # + if rc is True: + print "Warnning:" + print "Breakout port on platform %s is dangerous !!!" % (platform) + print "Please double-check make sure port %s can be configured to %s" % (port, opt) + + return rc + +# +# check breakout option valid +# configure files existing +# +def check_vaildation(platform, hwsku, port, opt): + + ini_file = get_ini_file(platform, hwsku) + + ports = get_bkout_ports(port, opt) + if ports == None: + print("Wrong interface name:%s" % (port)) + return False + + ### need re-visit + idx = port.split()[0].split(INTERFACE_KEY,1)[1] + + if int(idx) % (get_bkout_lanes(opt) / get_bkout_step(opt)) != 0: + print("Can not work on port:%s" % (port)) + return False + + f_in = open(ini_file, 'r') + + ini_ports = [] + ini_lanes = [] + port_found = 0 + title = [] + + for line in f_in.readlines(): + line = line.lstrip() + line = line.strip() + if len(line) == 0: + continue + + if re.search("^#", line) is not None: + # The current format is: # name lanes alias index speed + # Where the ordering of the columns can vary + title = line.split()[1:] + continue + + + line_port = line.split()[0] + + ### Check breakout case + if get_is_bkout(opt): + if line_port == port: + port_found += 1 + oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) + if len(olanes) < get_bkout_lanes(opt): + print("port %s can not breakout to %s." % (port, opt)) + f_in.close() + return False + else: + if line_port in ports: + port_found += 1 + oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) + ini_ports.append(line_port) + ini_lanes += olanes + + f_in.close() + + if get_is_bkout(opt) and port_found != 1: + if port_found == 0: + print("port %s does not exist." % (port)) + if port_found > 1: + print("Duplicate(%d) port %s found in INI file." % (port_found, port)) + return False + + if not get_is_bkout(opt): + if len(ini_lanes) == 0: + print("port %s does not exist." % (port)) + return False + + return True + + +def process_args(argv): + verbose = 0 + cust = "./cust_platform.json" + list = False + port = None + opt = None + + try: + opts, args = getopt.getopt(argv, "hlvc:p:o:", \ + ["help", "list", "verbose", "cust=", "port=", "opt="]) + + for opt,arg in opts: + if opt in ('-h','--help'): + usage() + return + if opt in ('-l', '--list'): + list = True + if opt in ('-v', '--verbose'): + verbose = 1 + if opt in ('-c', '--cust'): + cust = arg + if opt in ('-p', '--port'): + port = arg + if opt in ('-o', '--option'): + opt = arg + except getopt.GetoptError: + print("Error: Invalid option") + sys.exit(1) + + #print("# Custom Platform JSON: {}".format(cust)) + if os.path.isfile(cust): + print("# Custom Platform JSON detected, merging the platform info...") + try: + with open(cust) as fp: + sonic_platforms.update(json.load(fp)) + except: + pass + else: + print("# Custom Platform JSON not found") + + if list == True: + print("Supported platform list:") + for plat in sonic_platforms: + print("* {}".format(plat)) + sys.exit(0) + + if port == None or opt == None: + print "Error: must give -p [port] and -o [option]" + + usage() + sys.exit(1) + + return verbose, port, opt + +### Breakout interface +def main(argv): + global bko_dict + + if len(argv) > 0 and argv[0] == "-h": + usage() + return + + verbose, port, opt = process_args(argv) + """ + print verbose, port, opt + """ + + if not SIM_HOST: + platform = get_platform() + hwsku = get_hwsku() + else: + platform = 'xxx' + hwsku = 'yyy' + + bcm_file = get_bcm_file(platform, hwsku) + if "th3" in bcm_file: + bko_dict = bko_dict_8 + else: + bko_dict = bko_dict_4 + + if not bko_opt_valid(opt): + print("Invalid breakout option :%s" % (opt)) + print("Supported breakout option :%s" % (bko_dict.keys())) + return + + """ + print("Platform=[%s]" % (platform)) + print("hwsku=[%s]" % (hwsku)) + display_files(platform, hwsku) + """ + + if platform_checking(platform, hwsku, port, opt) is False: + return + + if check_vaildation(platform, hwsku, port, opt) == False: + print("breakout options checking failed.") + return + + break_a_port(port, opt, platform, hwsku) + + ### disable pre-emphasis workaround in 'led_proc_init.soc' + #file = get_led_file(platform, hwsku) + #if os.path.exists(file): + # run_command("sed -i 's/^rcload/#rcload/g' " + file) + +if __name__ == "__main__": + main(sys.argv[1:]) + + diff --git a/dockers/docker-pde/docker_init.sh b/dockers/docker-pde/docker_init.sh new file mode 100755 index 000000000000..b3cd98d273c3 --- /dev/null +++ b/dockers/docker-pde/docker_init.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -x + +start_bcm() +{ + [ -e /dev/linux-bcm-knet ] || mknod /dev/linux-bcm-knet c 122 0 + [ -e /dev/linux-user-bde ] || mknod /dev/linux-user-bde c 126 0 + [ -e /dev/linux-kernel-bde ] || mknod /dev/linux-kernel-bde c 127 0 +} + +PLATFORM_DIR=/usr/share/sonic/platform +HWSKU_DIR=/usr/share/sonic/hwsku + +mkdir -p /etc/sai.d/ + +if [ -f $HWSKU_DIR/sai.profile ]; then + cp $HWSKU_DIR/sai.profile /etc/sai.d/sai.profile + + SAI_CONFIG=`cat /etc/sai.d/sai.profile | rev | cut -d "/" -f1 | rev` + + ln -s $HWSKU_DIR/$SAI_CONFIG /tmp/brcm_sai_config.bcm + ln -s $HWSKU_DIR/port_config.ini /tmp/port_config.ini + + parse_port_config.py > /tmp/test_config.ini +fi + +start_bcm + +exec /usr/bin/supervisord + diff --git a/dockers/docker-pde/supervisord.conf b/dockers/docker-pde/supervisord.conf new file mode 100644 index 000000000000..58a32d833163 --- /dev/null +++ b/dockers/docker-pde/supervisord.conf @@ -0,0 +1,12 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[program:rsyslogd] +command=/bin/bash -c "rm -f /var/run/rsyslogd.pid && /usr/sbin/rsyslogd -n" +priority=1 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index c485254647b8..eeb945ddce22 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -188,7 +188,10 @@ start() { # Obtain our platform as we will mount directories with these names in each docker PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform` - {%- if docker_container_name == "database" %} + {%- if docker_container_name == "pde" %} + # PDE does not have access to database + HWSKU=`cat /usr/share/sonic/device/$PLATFORM/default_sku | cut -d ' ' -f1` + {%- elif docker_container_name == "database" %} # Don't mount HWSKU in {{docker_container_name}} container. HWSKU="" {%- else %} diff --git a/files/build_templates/pde.service.j2 b/files/build_templates/pde.service.j2 new file mode 100644 index 000000000000..f053b57ad576 --- /dev/null +++ b/files/build_templates/pde.service.j2 @@ -0,0 +1,22 @@ +[Unit] +Description=PDE container +{% if sonic_asic_platform == 'broadcom' %} +Requires=opennsl-modules.service +ConditionPathExists=!/usr/bin/swss.sh +{% endif %} + +After=updategraph.service +{% if sonic_asic_platform == 'broadcom' %} +After=opennsl-modules.service +{% endif %} + +Before= + +[Service] +User={{ sonicadmin_user }} +ExecStartPre=/usr/bin/{{ docker_container_name }}.sh start +ExecStart=/usr/bin/{{ docker_container_name }}.sh wait +ExecStop=/usr/bin/{{ docker_container_name }}.sh stop + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/one-pde-image.mk b/platform/broadcom/one-pde-image.mk new file mode 100644 index 000000000000..ac7d48a1fd9b --- /dev/null +++ b/platform/broadcom/one-pde-image.mk @@ -0,0 +1,45 @@ +# sonic broadcom one image installer + +SONIC_ONE_PDE_IMAGE = sonic-broadcom-pde.bin +$(SONIC_ONE_PDE_IMAGE)_MACHINE = broadcom +$(SONIC_ONE_PDE_IMAGE)_IMAGE_TYPE = onie +$(SONIC_ONE_PDE_IMAGE)_INSTALLS += $(BRCM_OPENNSL_KERNEL) +$(SONIC_ONE_PDE_IMAGE)_INSTALLS += $(PDDF_PLATFORM_MODULE) +$(SONIC_ONE_PDE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ + $(DELL_Z9264F_PLATFORM_MODULE) \ + $(DELL_Z9100_PLATFORM_MODULE) \ + $(DELL_S6100_PLATFORM_MODULE) \ + $(INGRASYS_S8900_54XC_PLATFORM_MODULE) \ + $(INGRASYS_S8900_64XC_PLATFORM_MODULE) \ + $(INGRASYS_S9100_PLATFORM_MODULE) \ + $(INGRASYS_S8810_32Q_PLATFORM_MODULE) \ + $(INGRASYS_S9200_64X_PLATFORM_MODULE) \ + $(ACCTON_AS7712_32X_PLATFORM_MODULE) \ + $(ACCTON_AS5712_54X_PLATFORM_MODULE) \ + $(ACCTON_AS7816_64X_PLATFORM_MODULE) \ + $(ACCTON_AS7716_32X_PLATFORM_MODULE) \ + $(ACCTON_AS7312_54X_PLATFORM_MODULE) \ + $(ACCTON_AS7326_56X_PLATFORM_MODULE) \ + $(ACCTON_AS7716_32XB_PLATFORM_MODULE) \ + $(ACCTON_AS6712_32X_PLATFORM_MODULE) \ + $(ACCTON_AS7726_32X_PLATFORM_MODULE) \ + $(ACCTON_AS4630_54PE_PLATFORM_MODULE) \ + $(ACCTON_MINIPACK_PLATFORM_MODULE) \ + $(ACCTON_AS5812_54X_PLATFORM_MODULE) \ + $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ + $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ + $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ + $(CEL_DX010_PLATFORM_MODULE) \ + $(CEL_HALIBURTON_PLATFORM_MODULE) \ + $(DELTA_AG9032V1_PLATFORM_MODULE) \ + $(DELTA_AG9064_PLATFORM_MODULE) \ + $(DELTA_AG5648_PLATFORM_MODULE) \ + $(DELTA_ET6248BRB_PLATFORM_MODULE) \ + $(QUANTA_IX1B_32X_PLATFORM_MODULE) \ + $(QUANTA_IX8_56X_PLATFORM_MODULE) \ + $(MITAC_LY1200_32X_PLATFORM_MODULE) \ + $(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE) \ + $(ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE) \ + $(BRCM_XLR_GTS_PLATFORM_MODULE) +$(SONIC_ONE_PDE_IMAGE)_DOCKERS += $(DOCKER_PDE) $(DOCKER_PLATFORM_MONITOR) $(DOCKER_DATABASE) +SONIC_INSTALLERS += $(SONIC_ONE_PDE_IMAGE) diff --git a/rules/config b/rules/config index 04af59ccd818..b9c4a93e4668 100644 --- a/rules/config +++ b/rules/config @@ -44,6 +44,9 @@ DEFAULT_PASSWORD = YourPaSsWoRd # If not set (default behavior) the default minigraph built into the image will be used. # ENABLE_DHCP_GRAPH_SERVICE = y +# ENABLE_PDE - Enable platform development enviroment +# ENABLE_PDE = y + # SHUTDOWN_BGP_ON_START - if set to y all bgp sessions will be in admin down state when # bgp service starts. # SHUTDOWN_BGP_ON_START = y diff --git a/rules/docker-pde.mk b/rules/docker-pde.mk new file mode 100644 index 000000000000..4edc31255a12 --- /dev/null +++ b/rules/docker-pde.mk @@ -0,0 +1,46 @@ +# Docker image for SONiC Platform Development Environment (PDE) + + +ifeq ($(ENABLE_PDE), y) + +DOCKER_PDE_STEM = docker-pde +DOCKER_PDE = $(DOCKER_PDE_STEM).gz +DOCKER_PDE_DBG = $(DOCKER_PDE_STEM)-$(DBG_IMAGE_MARK).gz + +$(DOCKER_PDE)_PATH = $(DOCKERS_PATH)/$(DOCKER_PDE_STEM) + +$(DOCKER_PDE)_DEPENDS += $(PYTHON_NETIFACES) +ifeq ($(CONFIGURED_PLATFORM),broadcom) +$(DOCKER_PDE)_DEPENDS += $(BRCM_SAI) $(SONIC_PLATFORM_PDE) +endif +$(DOCKER_PDE_RDEPENDS += $(PYTHON_NETIFACES) + +$(DOCKER_PDE)_PYTHON_DEBS += $(SONIC_UTILS) +$(DOCKER_PDE)_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY2) + +$(DOCKER_PDE)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS) +$(DOCKER_PDE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES) + +$(DOCKER_PDE)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_STRETCH) + +SONIC_DOCKER_IMAGES += $(DOCKER_PDE) +SONIC_STRETCH_DOCKERS += $(DOCKER_PDE) +SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_PDE) + +SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_PDE_DBG) +SONIC_DOCKER_DBG_IMAGES += $(DOCKER_PDE_DBG) +SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_PDE_DBG) + +$(DOCKER_PDE)_CONTAINER_NAME = pde +$(DOCKER_PDE)_RUN_OPT += --net=host --privileged -t +$(DOCKER_PDE)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_PDE)_RUN_OPT += -v /host/machine.conf:/host/machine.conf:ro +$(DOCKER_PDE)_RUN_OPT += -v /usr/lib/python2.7/dist-packages:/usr/share/sonic/classes:ro +$(DOCKER_PDE)_RUN_OPT += -v /var/log/syslog:/var/log/syslog:ro +$(DOCKER_PDE)_RUN_OPT += -v /lib/modules:/lib/modules:ro +$(DOCKER_PDE)_RUN_OPT += -v /boot:/boot:ro + +$(DOCKER_PDE)_BASE_IMAGE_FILES += port_breakout.py:/usr/local/bin/port_breakout.py +$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-test-harness:/usr/local/bin/pde-test-harness + +endif diff --git a/rules/sonic-pde-tests.mk b/rules/sonic-pde-tests.mk new file mode 100644 index 000000000000..a6b95da35611 --- /dev/null +++ b/rules/sonic-pde-tests.mk @@ -0,0 +1,17 @@ +# sonic pdk package +# +# NOTE: sonic-config-engine is a build-time dependency of sonic-utilities +# due to unit tests which are run during the build. However, +# sonic-platform-common and swsssdk are runtime dependencies, and should be +# added here also. However, the current build system assumes all runtime +# dependencies are .deb packages. +# +# TODO: Create a way to specify both .deb and .whl runtime dependencies +# then add the aforementioned runtime dependencies here. +# + +SONIC_PLATFORM_PDE = sonic-platform-pde_1.0_amd64.deb +$(SONIC_PLATFORM_PDE)_SRC_PATH = $(SRC_PATH)/sonic-platform-pdk-pde +$(SONIC_PLATFORM_PDE)_DEPENDS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(SWIG) + +SONIC_DPKG_DEBS += $(SONIC_PLATFORM_PDE) diff --git a/slave.mk b/slave.mk index f81895f74dd2..d01c2f86e279 100644 --- a/slave.mk +++ b/slave.mk @@ -190,6 +190,7 @@ $(info "ENABLE_ORGANIZATION_EXTENSIONS" : "$(ENABLE_ORGANIZATION_EXTENSIONS)") $(info "HTTP_PROXY" : "$(HTTP_PROXY)") $(info "HTTPS_PROXY" : "$(HTTPS_PROXY)") $(info "ENABLE_SYSTEM_TELEMETRY" : "$(ENABLE_SYSTEM_TELEMETRY)") +$(info "ENABLE_PDE" : "$(ENABLE_PDE)") $(info "SONIC_DEBUGGING_ON" : "$(SONIC_DEBUGGING_ON)") $(info "SONIC_PROFILING_ON" : "$(SONIC_PROFILING_ON)") $(info "KERNEL_PROCURE_METHOD" : "$(KERNEL_PROCURE_METHOD)") @@ -639,6 +640,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export sonic_asic_platform="$(patsubst %-$(CONFIGURED_ARCH),%,$(CONFIGURED_PLATFORM))" export enable_organization_extensions="$(ENABLE_ORGANIZATION_EXTENSIONS)" export enable_dhcp_graph_service="$(ENABLE_DHCP_GRAPH_SERVICE)" + export enable_pde="$(ENABLE_PDE)" export shutdown_bgp_on_start="$(SHUTDOWN_BGP_ON_START)" export enable_pfcwd_on_start="$(ENABLE_PFCWD_ON_START)" export installer_debs="$(addprefix $(STRETCH_DEBS_PATH)/,$($*_INSTALLS))" @@ -680,16 +682,19 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ DEBUG_SRC_ARCHIVE_FILE="$(DBG_SRC_ARCHIVE_FILE)" \ scripts/dbg_files.sh + DEBUG_IMG="$(INSTALL_DEBUG_TOOLS)" \ DEBUG_SRC_ARCHIVE_FILE="$(DBG_SRC_ARCHIVE_FILE)" \ USERNAME="$(USERNAME)" \ PASSWORD="$(PASSWORD)" \ + BUILD_TARGET="$@" \ ./build_debian.sh $(LOG) USERNAME="$(USERNAME)" \ PASSWORD="$(PASSWORD)" \ TARGET_MACHINE=$($*_MACHINE) \ IMAGE_TYPE=$($*_IMAGE_TYPE) \ + BUILD_TARGET="$@" \ ./build_image.sh $(LOG) $(foreach docker, $($*_DOCKERS), \ From 2bef8194a207ba4b519a6124e6473b8f13f04563 Mon Sep 17 00:00:00 2001 From: William Schwartz Date: Wed, 11 Mar 2020 11:33:30 -0700 Subject: [PATCH 2/5] Addressing community review comments --- dockers/docker-pde/Dockerfile | 54 -- dockers/docker-pde/Dockerfile.j2 | 1 - .../base_image_files/port_breakout.py | 833 ------------------ rules/config | 2 + 4 files changed, 2 insertions(+), 888 deletions(-) delete mode 100644 dockers/docker-pde/Dockerfile delete mode 100755 dockers/docker-pde/base_image_files/port_breakout.py diff --git a/dockers/docker-pde/Dockerfile b/dockers/docker-pde/Dockerfile deleted file mode 100644 index 46002fed9e25..000000000000 --- a/dockers/docker-pde/Dockerfile +++ /dev/null @@ -1,54 +0,0 @@ - -FROM docker-config-engine-stretch - -ARG docker_container_name -ENV PYTHONPATH=/usr/share/sonic/platform - -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 - -# Update apt's cache of available packages -RUN apt-get update && apt-get install -y ipmitool telnet busybox kmod - -RUN pip install pytest pexpect - -# Copy locally-built Debian package dependencies -COPY \ -debs/libsaibcm_3.5.3.1m-25_amd64.deb debs/sonic-platform-pde_1.0_amd64.deb /debs/ - -# Install locally-built Debian packages and implicitly install their dependencies -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; \ -dpkg_apt /debs/libsaibcm_3.5.3.1m-25_amd64.deb; \ -dpkg_apt /debs/sonic-platform-pde_1.0_amd64.deb - -# Copy locally-built Debian package dependencies -COPY \ -python-debs/python-sonic-utilities_1.2-1_all.deb /debs/ - -# Install locally-built Debian packages and implicitly install their dependencies -RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; }; dpkg_apt /debs/python-sonic-utilities_1.2-1_all.deb - -# Copy locally-built Python wheel dependencies -COPY \ -python-wheels/sonic_platform_common-1.0-py2-none-any.whl /python-wheels/ - -# Install locally-built Python wheel dependencies -RUN pip install \ -/python-wheels/sonic_platform_common-1.0-py2-none-any.whl - - - -# Clean up -RUN apt-get clean -y; \ - apt-get autoclean -y; \ - apt-get autoremove -y -RUN rm -rf /debs ~/.cache - -RUN mkdir -p /home/pde - -COPY ["base_image_files/port_breakout.py", "/usr/local/bin/"] -COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] -COPY ["docker_init.sh", "/usr/bin/"] -ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-pde/Dockerfile.j2 b/dockers/docker-pde/Dockerfile.j2 index 515a6d492206..bc01740468d6 100644 --- a/dockers/docker-pde/Dockerfile.j2 +++ b/dockers/docker-pde/Dockerfile.j2 @@ -66,7 +66,6 @@ RUN rm -rf /debs ~/.cache RUN mkdir -p /home/pde -COPY ["base_image_files/port_breakout.py", "/usr/local/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["docker_init.sh", "/usr/bin/"] ENTRYPOINT ["/usr/bin/docker_init.sh"] diff --git a/dockers/docker-pde/base_image_files/port_breakout.py b/dockers/docker-pde/base_image_files/port_breakout.py deleted file mode 100755 index 0060f0e96d28..000000000000 --- a/dockers/docker-pde/base_image_files/port_breakout.py +++ /dev/null @@ -1,833 +0,0 @@ -#! /usr/bin/python -u - -import os -import sys -import re -import getopt -import copy -import json -import shutil -import os.path -import subprocess - -SIM_HOST = False - -SAI_PROFILE_DELIMITER = '=' -INTERFACE_KEY="Ethernet" -if not SIM_HOST: - NEW_FILE_EXT="" -else: - NEW_FILE_EXT="" - -sonic_platforms = { - "x86_64-accton_as9716_32d-r0": { - "breakout": { - "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "1x400", "4x100", "4x50", "2x100", "2x200", "4x25", "4x10" ] - } - }, - "x86_64-accton_as7326_56x-r0": { - "breakout": { - "48,52,56,60,64,68,72": [ "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-accton_as7712_32x-r0": { - "breakout": { - "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-accton_as7816_64x-r0": { - "breakout": { - "0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120": [ "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-accton_as7726_32x-r0": { - "breakout": { - "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120": [ "4x25", "4x10", "1x100", "1x40" ] - } - }, - "x86_64-delta_ag9032v1-r0": { - "breakout": { - "0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124": [ "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-quanta_ix4_bwde-r0": { - "breakout": { - "128,132,136,140,144,148,152,156,192,196,200,204,208,212,216,220": [ - "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-quanta_ix8_rglbmc-r0": { - "breakout": { - "48,52,56,60,64,68,72": [ "4x10", "4x25", "1x100", "1x40" ] - } - }, - "x86_64-quanta_ix9_bwde-r0": { - "breakout": { - "0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248": [ "1x400", "4x100", "4x25", "4x10", "4x50", "2x200", "2x100" ] - } - } -} - -##################################################################################################### -### Platform related code - -if not SIM_HOST: - def get_platform(): - cmd = "cat /host/machine.conf | grep onie_platform | cut -d '=' -f 2" - pin = subprocess.Popen(cmd, - shell=True, - close_fds=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - id = pin.communicate()[0] - id = id.strip() - return id - - def get_platform_path(): - path = "/usr/share/sonic/platform" - if os.path.exists(path): - return path - path = "/usr/share/sonic/device/" + get_platform() - return path - - def get_hwsku(): - dir = get_platform_path() - pin = subprocess.Popen("cat " + dir + "/default_sku | cut -d ' ' -f 1", - shell=True, - close_fds=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - id = pin.communicate()[0] - id = id.strip() - return id - - - # run command - def run_command(command, display_cmd=False, ignore_error=False, print_to_console=True): - ### - ### Run bash command and print output to stdout - ### - if display_cmd == True: - print("Running command: " + command) - - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) - (out, err) = proc.communicate() - - if len(out) > 0 and print_to_console: - print(out) - - if proc.returncode != 0 and not ignore_error: - sys.exit(proc.returncode) - - return out, err - - def get_bcm_file(platform, hwsku): - sai_profile_kvs = {} - - sai_file = get_platform_path() + "/" + hwsku + "/" + "sai.profile" - command = "cat "+ sai_file - sai_profile_content, _ = run_command(command, print_to_console=False) - - for line in sai_profile_content.split('\n'): - if not SAI_PROFILE_DELIMITER in line: - continue - key, value = line.split(SAI_PROFILE_DELIMITER) - sai_profile_kvs[key] = value.strip() - - try: - sai_xml_path = sai_profile_kvs['SAI_INIT_CONFIG_FILE'] - except KeyError: - print >> sys.stderr, "Failed to get SAI XML from sai profile" - sys.exit(1) - - bcm_file = "config.bcm" - if not SIM_HOST: - bcm_file = get_platform_path() + "/" + hwsku + "/" + os.path.basename(sai_xml_path) - - return bcm_file - -##################################################################################################### - - -def get_ini_file(platform, hwsku): - if not SIM_HOST: - ini_file = get_platform_path() + '/' + hwsku + '/' + "port_config.ini" - else: - ini_file = "port_config.ini" - return ini_file - -def get_cfg_file(platform, hwsku): - if not SIM_HOST: - cfg_file = "/etc/sonic/config_db.json" - else: - cfg_file = "config_db.json" - return cfg_file - -def get_led_file(platform, hwsku): - if not SIM_HOST: - led_file = get_platform_path() + "/led_proc_init.soc" - else: - led_file = "led_proc_init.soc" - return led_file - -def display_files(platform, hwsku): - print("BCM File:[%s]" % (get_bcm_file(platform, hwsku))) - print("INI File:[%s]" % (get_ini_file(platform, hwsku))) - print("CFG File:[%s]" % (get_cfg_file(platform, hwsku))) - -bko_dict_4 = { - "1x100": { "lanes":4, "speed":100, "step":4, "bko":0, "name": "hundredGigE" }, - "1x40": { "lanes":4, "speed":40, "step":4, "bko":0, "name": "fourtyGigE" }, - "4x10": { "lanes":4, "speed":10, "step":1, "bko":1, "name": "tenGigE" }, - "4x25": { "lanes":4, "speed":25, "step":1, "bko":1, "name": "twentyfiveGigE" }, -} - -bko_dict_8 = { - "1x400": { "lanes":8, "speed":400, "step":8, "bko":0, "name": "fourhundredGigE" }, - "2x200": { "lanes":8, "speed":200, "step":4, "bko":1, "name": "twohundredGigE" }, - "2x100": { "lanes":8, "speed":100, "step":4, "bko":1, "name": "hundredGigE" }, - "4x100": { "lanes":8, "speed":100, "step":2, "bko":1, "name": "hundredGigE" }, - "4x50": { "lanes":8, "speed":50, "step":2, "bko":1, "name": "fiftyGigE" }, - "4x25": { "lanes":4, "speed":25, "step":1, "bko":1, "name": "twentyfiveGigE" }, - "4x10": { "lanes":4, "speed":10, "step":1, "bko":1, "name": "tenGigE" }, -} - -bko_dict = bko_dict_4 - -# -# Get breakout step: -# -def bko_opt_valid(opt): - if opt in bko_dict: - return True - else: - return False - -def get_bkout_step(opt): - return bko_dict[opt]["step"] - -def get_bkout_subport_name(opt): - return bko_dict[opt]["name"] - -def get_bkout_subport_speed(opt): - return bko_dict[opt]["speed"] - -def get_is_bkout(opt): - return bko_dict[opt]["bko"] - -def get_bkout_lanes(opt): - return bko_dict[opt]["lanes"] - -def get_bkout_ports(port, opt): - lanes = 4 - step = 1 - - if not port.startswith(INTERFACE_KEY): - return None - - idx = port.split()[0].split(INTERFACE_KEY,1)[1] - if not idx.isdigit(): - return None - - ports = [] - for i in range(0, lanes, step): - portx = INTERFACE_KEY + str(int(idx) + (i/step)) - ports.append(portx) - return ports - - -# -# Breakout a port in INI file: -# Ethernet48 81,82,83,84 hundredGigE13 - -# Change to -# Ethernet48 81 twentyfiveGigE13:1 -# Ethernet49 82 twentyfiveGigE13:2 -# Ethernet50 83 twentyfiveGigE13:3 -# Ethernet51 84 twentyfiveGigE13:4 - -# -# Ethernet48 81,82,83,84 hundredGigE13 -# return: -# "48" -# ["81", "82", "83", "84"] -# "hundredGigE" -# "13" - - -def get_info_in_ini(line, title): - idx = line.split()[0].split(INTERFACE_KEY,1)[1] - lanes = line.split()[1].split(",") - name = line.split()[2] - temp = name.split(":")[0] - porti = re.sub('.*?([0-9]*)$',r'\1', temp) - - if "index" in title: - fp_idx = int(line.split()[title.index("index")]) - else: - fp_idx = None - return idx, lanes, name, porti, fp_idx - -def break_in_ini(port, ini_file, opt): - print("Breaking port %s to %s in ini ..." % (port, opt)) - - bak_file = ini_file + ".bak" - shutil.copy(ini_file, bak_file) - - new_file = ini_file + NEW_FILE_EXT - step = get_bkout_step(opt) - - f_in = open(bak_file, 'r') - f_out = open(new_file, 'w') - - first_port = True - title = [] - - for line in f_in.readlines(): - line.strip() - if len(line.rstrip()) == 0: - continue - - if re.search("^#", line) is not None: - # The current format is: # name lanes alias index speed - # Where the ordering of the columns can vary - if len(title) == 0: - title = line.split()[1:] - print title - f_out.write(line) - continue - - line = line.lstrip() - line_port = line.split()[0] - - if line_port in get_bkout_ports(port, opt): - oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) - - if get_is_bkout(opt) and len(olanes) < get_bkout_lanes(opt): - print("Port %s Already breakout ..." % (port)) - print("Existing ...") - f_in.close() - f_out.close() - shutil.copy(bak_file, new_file) - - sys.exit() - - # - # Non-Breakout case - # - if not get_is_bkout(opt) and not first_port: - print("--- {} removed".format(line_port)) - continue - - if not get_is_bkout(opt) and first_port: - idx = oidx - lanes = [] - for i in range(0, get_bkout_lanes(opt), 1): - lanes.append(str(int(olanes[0])+i)) - porti = oporti - - if get_is_bkout(opt): - idx = oidx - lanes = olanes - porti = oporti - - # - # original string: - # Ethernet20 69,70,71,72 hundredGigE6 - # - print(" %s" % line.rstrip()) - - # Generate new interface line - for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): - # - # Ethernet20 - # - temp_str = "Ethernet%d" % (int(idx) + (i/step)) - new_intf = "%-15s " % temp_str - - temp_str = lanes[i+0] - # - # generate 69 - # - for j in range(1, step): - temp_str += ",%s" % (lanes[i+j]) - new_intf += "%-21s " % temp_str - - # - # Generate twentyfiveGigE6:i - # - if get_is_bkout(opt): - temp_str = "%s%s:%d" % (get_bkout_subport_name(opt), porti, (i/step + 1)) - else: - temp_str = "%s%s" % (get_bkout_subport_name(opt), porti) - - new_intf += "%-19s " % temp_str - - # - # index - # - if fp_idx is not None: - temp_str = "%d" % (fp_idx) - new_intf += "%-6s " % temp_str - - - # - # speed - # - temp_str = "%d000" % get_bkout_subport_speed(opt) - new_intf += "%-10s " % temp_str - - # - # valid_speeds - # - if 'valid_speeds' in title: - temp_str = str(get_bkout_subport_speed(opt) * 1000) - if get_bkout_subport_speed(opt) == 100: - if get_bkout_step(opt) == 4: - # NRZ mode - temp_str = "100000,40000" - else: - # PAM4 mode - temp_str = "100000" - elif get_bkout_subport_speed(opt) == 40: - temp_str = "100000,40000" - - new_intf += "%s" % temp_str - - - if not get_is_bkout(opt) and first_port: - print "===>" + new_intf - new_intf += "\n" - f_out.write(new_intf) - first_port = False - if get_is_bkout(opt): - print "===>" + new_intf - new_intf += "\n" - f_out.write(new_intf) - - else: - f_out.write(line) - - print "--------------------------------------------------------" - f_in.close() - f_out.close() - - print lanes - return lanes - -# -# Parse logic port, phyical port, speed from bcm -# -def parse_port_bcm(bcm_str): - lp = bcm_str.split("=")[0].split("_")[1] - pp = bcm_str.split("=")[1].split(":")[0] - sp = bcm_str.split("=")[1].split(":")[1] - - return lp, pp, sp - -# -# portmap_84=81:100 -# -# portmap_84=81:25 -# portmap_85=82:25 -# portmap_86=83:25 -# portmap_87=84:25 -# -# -def break_in_bcm(port, lanes, bcm_file, opt, platform): - print("Breaking %s to %s in bcm ..." % (port, opt)) - - bak_file = bcm_file + ".bak" - shutil.copy(bcm_file, bak_file) - - new_file = bcm_file + NEW_FILE_EXT - step = get_bkout_step(opt) - - f_in = open(bak_file, 'r') - f_out = open(new_file, 'w') - - first_port = True - fec_removed = False - print lanes - for oline in f_in.readlines(): - line = oline.lstrip() - - if line.startswith('#'): - f_out.write(oline) - continue - - ### when running in unbreakout mode, the FEC setting per breakout should be removed - if not get_is_bkout(opt) and line.startswith("port_fec") and fec_removed: - continue - if not line.startswith("portmap"): - f_out.write(oline) - continue - - ### logic port, phyical port, speed - lp, pp, sp = parse_port_bcm(line) - if pp not in lanes: - f_out.write(oline) - fec_removed = False - continue - - if not get_is_bkout(opt): - fec_removed = True - - if not get_is_bkout(opt) and not first_port: - print("--- portmap_{} removed".format(lp)) - continue - - #### generate new port map - print(" %s" % line.rstrip()) - for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): - if '.' in lp: - nlp = lp.split('.')[0] - unit = lp.split('.')[1] - new_intf = "portmap_%d.%s=%d:%d:%d" % ((int(nlp) + (i / step)), unit, (int(pp)+i), get_bkout_subport_speed(opt), get_bkout_step(opt)) - else: - new_intf = "portmap_%d=%d:%d:%d" % ((int(lp) + (i / step)), (int(pp)+i), get_bkout_subport_speed(opt), get_bkout_step(opt)) - fec_intf = "port_fec_"+ str(int(lp) + (i/step)) +"=3" - - if not get_is_bkout(opt) and first_port: - f_out.write(new_intf) - f_out.write("\n") - print "===>" + new_intf - first_port = False - if get_is_bkout(opt): - f_out.write(new_intf) - f_out.write("\n") - ### generate default FEC only for IX9 platform - if opt == "4x100" and platform == "x86_64-quanta_ix9_bwde-r0": - f_out.write(fec_intf) - f_out.write("\n") - print "===>" + new_intf - - print "--------------------------------------------------------" - f_in.close() - f_out.close() - -# -# breakout ports in json file -# -def break_in_cfg(port, cfg_file, lanes, opt): - if not os.access(os.path.dirname(cfg_file), os.W_OK): - print("Skipping config_db.json updates for a write permission issue") - return - - step = get_bkout_step(opt) - print("Breaking %s to %s in cfg ... " % (port, opt)) - - bak_file = cfg_file + ".bak" - shutil.copy(cfg_file, bak_file) - - new_file = cfg_file + NEW_FILE_EXT - - with open(bak_file) as f: - data = json.load(f) - - with open(cfg_file, 'w') as outfile: - json.dump(data, outfile, indent=4, sort_keys=True) - - ### - ### Process in 'INTERFACE' - ### - if 'INTERFACE' in data: - for key, value in sorted(data['INTERFACE'].iteritems()): - pkey = key.split('|')[0] - if port == pkey: - data['INTERFACE'].pop(key) - - ### - ### Process in 'PORT' - - - ### remove port instance in data - ### - ports = get_bkout_ports(port, opt) - for x in ports: - if data['PORT'].get(x) != None: - port_instance = data['PORT'].get(x) - data['PORT'].pop(x) - print " ", x, port_instance - - idx = port.split()[0].split(INTERFACE_KEY,1)[1] - porti = re.sub('.*?([0-9]*)$',r'\1', port_instance['alias'].split(":")[0]) - - for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): - - if get_is_bkout(opt): - temp_str = lanes[i] - for j in range(1, step): - temp_str += ",%s" % (lanes[i+j]) - port_instance['lanes'] = temp_str - port_instance['alias'] = get_bkout_subport_name(opt) + porti + ':' + str(i/step + 1) - else: - port_instance['alias'] = get_bkout_subport_name(opt) + porti - port_instance['lanes'] = ','.join(str(e) for e in lanes) - - port_instance['speed'] = str(get_bkout_subport_speed(opt)) + "000" - port_instance['valid_speeds'] = str(get_bkout_subport_speed(opt)) + "000" - - new_port = INTERFACE_KEY + str(int(idx) + (i/step)) - xxx = copy.deepcopy(port_instance) - data['PORT'][new_port] = xxx - ### print data['PORT'][new_port] - - for i in range(0, min(len(lanes), get_bkout_lanes(opt)), step): - new_port = INTERFACE_KEY + str(int(idx) + (i/step)) - print "===>", new_port, data['PORT'][new_port] - - with open(new_file, 'w') as outfile: - json.dump(data, outfile, indent=4, sort_keys=True) - - print "--------------------------------------------------------" - -def break_a_port(port, opt, platform, hwsku): - ini_file = get_ini_file(platform, hwsku) - bcm_file = get_bcm_file(platform, hwsku) - cfg_file = get_cfg_file(platform, hwsku) - - lanes = break_in_ini(port, ini_file, opt) - break_in_bcm(port, lanes, bcm_file, opt, platform) - break_in_cfg(port, cfg_file, lanes, opt) - -def usage(): - print "Usage: " + sys.argv[0] + " interface 4x100|4x25" - print "Breakout None-breaokout a port" - print "Options:" - print " -p port" - print " -o breakout option" - for k in bko_dict: - print " %s" % k - print " " - print "Example:" - print " Breakout port Ethernet4 to 4x10G" - print " %s -p Ethernet4 -o 4x10" % (sys.argv[0]) - print " None-Breakout port Ethernet4 to 40G" - print " %s -p Ethernet4 -o 1x40" % (sys.argv[0]) - print " " - print "Note:" - print " Make sure understand which ports are able to breakout before execute command." - print " Make backup below config files" - print " - /usr/share/sonic/device/[platform]/[hwsku]/[config.bcm]" - print " - /usr/share/sonic/device/[platform]/[hwsku]/port_config.ini" - print " - /etc/sonic/config_db.json" - - sys.exit(1) - -def platform_checking(platform, hwsku, port, opt): - # - # default allow breakout ports on any platforms and ports - # - rc = True - - if not port.startswith(INTERFACE_KEY): - print "Wrong port name %s ..." % (port) - return False - - - if platform in sonic_platforms and 'breakout' in sonic_platforms[platform]: - idx = port.split()[0].split(INTERFACE_KEY,1)[1] - for keys in sonic_platforms[platform]['breakout']: - if idx in keys.split(',') and opt in sonic_platforms[platform]['breakout'][keys]: - print "Breakout port %s to %s in platform %s is allowed." % (port, opt, platform) - return True - else: - print "Error: Breakout port %s to %s in platform %s is NOT allowed !!!" % (port, opt, platform) - rc = False - - - # - # Platforms not in sonic_platforms, or not defined 'breakout' - # - if rc is True: - print "Warnning:" - print "Breakout port on platform %s is dangerous !!!" % (platform) - print "Please double-check make sure port %s can be configured to %s" % (port, opt) - - return rc - -# -# check breakout option valid -# configure files existing -# -def check_vaildation(platform, hwsku, port, opt): - - ini_file = get_ini_file(platform, hwsku) - - ports = get_bkout_ports(port, opt) - if ports == None: - print("Wrong interface name:%s" % (port)) - return False - - ### need re-visit - idx = port.split()[0].split(INTERFACE_KEY,1)[1] - - if int(idx) % (get_bkout_lanes(opt) / get_bkout_step(opt)) != 0: - print("Can not work on port:%s" % (port)) - return False - - f_in = open(ini_file, 'r') - - ini_ports = [] - ini_lanes = [] - port_found = 0 - title = [] - - for line in f_in.readlines(): - line = line.lstrip() - line = line.strip() - if len(line) == 0: - continue - - if re.search("^#", line) is not None: - # The current format is: # name lanes alias index speed - # Where the ordering of the columns can vary - title = line.split()[1:] - continue - - - line_port = line.split()[0] - - ### Check breakout case - if get_is_bkout(opt): - if line_port == port: - port_found += 1 - oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) - if len(olanes) < get_bkout_lanes(opt): - print("port %s can not breakout to %s." % (port, opt)) - f_in.close() - return False - else: - if line_port in ports: - port_found += 1 - oidx, olanes, name, oporti, fp_idx = get_info_in_ini(line, title) - ini_ports.append(line_port) - ini_lanes += olanes - - f_in.close() - - if get_is_bkout(opt) and port_found != 1: - if port_found == 0: - print("port %s does not exist." % (port)) - if port_found > 1: - print("Duplicate(%d) port %s found in INI file." % (port_found, port)) - return False - - if not get_is_bkout(opt): - if len(ini_lanes) == 0: - print("port %s does not exist." % (port)) - return False - - return True - - -def process_args(argv): - verbose = 0 - cust = "./cust_platform.json" - list = False - port = None - opt = None - - try: - opts, args = getopt.getopt(argv, "hlvc:p:o:", \ - ["help", "list", "verbose", "cust=", "port=", "opt="]) - - for opt,arg in opts: - if opt in ('-h','--help'): - usage() - return - if opt in ('-l', '--list'): - list = True - if opt in ('-v', '--verbose'): - verbose = 1 - if opt in ('-c', '--cust'): - cust = arg - if opt in ('-p', '--port'): - port = arg - if opt in ('-o', '--option'): - opt = arg - except getopt.GetoptError: - print("Error: Invalid option") - sys.exit(1) - - #print("# Custom Platform JSON: {}".format(cust)) - if os.path.isfile(cust): - print("# Custom Platform JSON detected, merging the platform info...") - try: - with open(cust) as fp: - sonic_platforms.update(json.load(fp)) - except: - pass - else: - print("# Custom Platform JSON not found") - - if list == True: - print("Supported platform list:") - for plat in sonic_platforms: - print("* {}".format(plat)) - sys.exit(0) - - if port == None or opt == None: - print "Error: must give -p [port] and -o [option]" - - usage() - sys.exit(1) - - return verbose, port, opt - -### Breakout interface -def main(argv): - global bko_dict - - if len(argv) > 0 and argv[0] == "-h": - usage() - return - - verbose, port, opt = process_args(argv) - """ - print verbose, port, opt - """ - - if not SIM_HOST: - platform = get_platform() - hwsku = get_hwsku() - else: - platform = 'xxx' - hwsku = 'yyy' - - bcm_file = get_bcm_file(platform, hwsku) - if "th3" in bcm_file: - bko_dict = bko_dict_8 - else: - bko_dict = bko_dict_4 - - if not bko_opt_valid(opt): - print("Invalid breakout option :%s" % (opt)) - print("Supported breakout option :%s" % (bko_dict.keys())) - return - - """ - print("Platform=[%s]" % (platform)) - print("hwsku=[%s]" % (hwsku)) - display_files(platform, hwsku) - """ - - if platform_checking(platform, hwsku, port, opt) is False: - return - - if check_vaildation(platform, hwsku, port, opt) == False: - print("breakout options checking failed.") - return - - break_a_port(port, opt, platform, hwsku) - - ### disable pre-emphasis workaround in 'led_proc_init.soc' - #file = get_led_file(platform, hwsku) - #if os.path.exists(file): - # run_command("sed -i 's/^rcload/#rcload/g' " + file) - -if __name__ == "__main__": - main(sys.argv[1:]) - - diff --git a/rules/config b/rules/config index 30a06598ea10..87f91096c313 100644 --- a/rules/config +++ b/rules/config @@ -45,6 +45,8 @@ DEFAULT_PASSWORD = YourPaSsWoRd # ENABLE_DHCP_GRAPH_SERVICE = y # ENABLE_PDE - Enable platform development enviroment +# If set to y the PDE docker and associated tools and applications will be built as part of the +# SONiC image and present on the system after installation. # ENABLE_PDE = y # ENABLE_ZTP - installs Zero Touch Provisioning support. From 512b2764ac8b7d4f2387fd3b1271bb1dd1b03e7c Mon Sep 17 00:00:00 2001 From: William Schwartz Date: Thu, 18 Jun 2020 09:15:40 -0700 Subject: [PATCH 3/5] Updating build makefile changes for PDE --- {rules => platform/broadcom}/docker-pde.mk | 17 ++++++---- platform/broadcom/one-pde-image.mk | 38 ++-------------------- platform/broadcom/sonic-pde-tests.mk | 7 ++++ rules/sonic-pde-tests.mk | 17 ---------- 4 files changed, 20 insertions(+), 59 deletions(-) rename {rules => platform/broadcom}/docker-pde.mk (71%) create mode 100644 platform/broadcom/sonic-pde-tests.mk delete mode 100644 rules/sonic-pde-tests.mk diff --git a/rules/docker-pde.mk b/platform/broadcom/docker-pde.mk similarity index 71% rename from rules/docker-pde.mk rename to platform/broadcom/docker-pde.mk index 4edc31255a12..9a20b2f99962 100644 --- a/rules/docker-pde.mk +++ b/platform/broadcom/docker-pde.mk @@ -10,14 +10,16 @@ DOCKER_PDE_DBG = $(DOCKER_PDE_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_PDE)_PATH = $(DOCKERS_PATH)/$(DOCKER_PDE_STEM) $(DOCKER_PDE)_DEPENDS += $(PYTHON_NETIFACES) -ifeq ($(CONFIGURED_PLATFORM),broadcom) -$(DOCKER_PDE)_DEPENDS += $(BRCM_SAI) $(SONIC_PLATFORM_PDE) -endif +$(DOCKER_PDE)_DEPENDS += $(SONIC_PLATFORM_PDE) $(BRCM_SAI) + $(DOCKER_PDE_RDEPENDS += $(PYTHON_NETIFACES) $(DOCKER_PDE)_PYTHON_DEBS += $(SONIC_UTILS) $(DOCKER_PDE)_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY2) - +ifeq ($(PDDF_SUPPORT), y) +$(DOCKER_PDE)_PYTHON_WHEELS += $(PDDF_PLATFORM_API_BASE_PY2) +endif +$(DOCKER_PDE)_PYTHON_WHEELS += $(SONIC_DAEMON_BASE_PY2) $(DOCKER_PDE)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS) $(DOCKER_PDE)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES) @@ -40,7 +42,10 @@ $(DOCKER_PDE)_RUN_OPT += -v /var/log/syslog:/var/log/syslog:ro $(DOCKER_PDE)_RUN_OPT += -v /lib/modules:/lib/modules:ro $(DOCKER_PDE)_RUN_OPT += -v /boot:/boot:ro -$(DOCKER_PDE)_BASE_IMAGE_FILES += port_breakout.py:/usr/local/bin/port_breakout.py -$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-test-harness:/usr/local/bin/pde-test-harness +$(DOCKER_PDE)_RUN_OPT += -v /usr/share/sonic/device/pddf:/usr/share/sonic/device/pddf:ro +$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-test:/usr/local/bin/pde-test +$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-bench:/usr/local/bin/pde-bench +$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-stress:/usr/local/bin/pde-stress +$(DOCKER_PDE)_BASE_IMAGE_FILES += pde-bench-knet:/usr/local/bin/pde-bench-knet endif diff --git a/platform/broadcom/one-pde-image.mk b/platform/broadcom/one-pde-image.mk index ac7d48a1fd9b..da9ddd971dad 100644 --- a/platform/broadcom/one-pde-image.mk +++ b/platform/broadcom/one-pde-image.mk @@ -5,41 +5,7 @@ $(SONIC_ONE_PDE_IMAGE)_MACHINE = broadcom $(SONIC_ONE_PDE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_PDE_IMAGE)_INSTALLS += $(BRCM_OPENNSL_KERNEL) $(SONIC_ONE_PDE_IMAGE)_INSTALLS += $(PDDF_PLATFORM_MODULE) -$(SONIC_ONE_PDE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ - $(DELL_Z9264F_PLATFORM_MODULE) \ - $(DELL_Z9100_PLATFORM_MODULE) \ - $(DELL_S6100_PLATFORM_MODULE) \ - $(INGRASYS_S8900_54XC_PLATFORM_MODULE) \ - $(INGRASYS_S8900_64XC_PLATFORM_MODULE) \ - $(INGRASYS_S9100_PLATFORM_MODULE) \ - $(INGRASYS_S8810_32Q_PLATFORM_MODULE) \ - $(INGRASYS_S9200_64X_PLATFORM_MODULE) \ - $(ACCTON_AS7712_32X_PLATFORM_MODULE) \ - $(ACCTON_AS5712_54X_PLATFORM_MODULE) \ - $(ACCTON_AS7816_64X_PLATFORM_MODULE) \ - $(ACCTON_AS7716_32X_PLATFORM_MODULE) \ - $(ACCTON_AS7312_54X_PLATFORM_MODULE) \ - $(ACCTON_AS7326_56X_PLATFORM_MODULE) \ - $(ACCTON_AS7716_32XB_PLATFORM_MODULE) \ - $(ACCTON_AS6712_32X_PLATFORM_MODULE) \ - $(ACCTON_AS7726_32X_PLATFORM_MODULE) \ - $(ACCTON_AS4630_54PE_PLATFORM_MODULE) \ - $(ACCTON_MINIPACK_PLATFORM_MODULE) \ - $(ACCTON_AS5812_54X_PLATFORM_MODULE) \ - $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ - $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ - $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ - $(CEL_DX010_PLATFORM_MODULE) \ - $(CEL_HALIBURTON_PLATFORM_MODULE) \ - $(DELTA_AG9032V1_PLATFORM_MODULE) \ - $(DELTA_AG9064_PLATFORM_MODULE) \ - $(DELTA_AG5648_PLATFORM_MODULE) \ - $(DELTA_ET6248BRB_PLATFORM_MODULE) \ - $(QUANTA_IX1B_32X_PLATFORM_MODULE) \ - $(QUANTA_IX8_56X_PLATFORM_MODULE) \ - $(MITAC_LY1200_32X_PLATFORM_MODULE) \ - $(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE) \ - $(ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE) \ - $(BRCM_XLR_GTS_PLATFORM_MODULE) +$(SONIC_ONE_PDE_IMAGE)_LAZY_INSTALLS += $(SONIC_ONE_IMAGE_LAZY_INSTALLS) + $(SONIC_ONE_PDE_IMAGE)_DOCKERS += $(DOCKER_PDE) $(DOCKER_PLATFORM_MONITOR) $(DOCKER_DATABASE) SONIC_INSTALLERS += $(SONIC_ONE_PDE_IMAGE) diff --git a/platform/broadcom/sonic-pde-tests.mk b/platform/broadcom/sonic-pde-tests.mk new file mode 100644 index 000000000000..a7482625c87e --- /dev/null +++ b/platform/broadcom/sonic-pde-tests.mk @@ -0,0 +1,7 @@ +# sonic pde package + +SONIC_PLATFORM_PDE = sonic-platform-pde_1.0_amd64.deb +$(SONIC_PLATFORM_PDE)_SRC_PATH = $(SRC_PATH)/sonic-platform-pde +$(SONIC_PLATFORM_PDE)_DEPENDS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(SWIG) + +SONIC_DPKG_DEBS += $(SONIC_PLATFORM_PDE) diff --git a/rules/sonic-pde-tests.mk b/rules/sonic-pde-tests.mk deleted file mode 100644 index a6b95da35611..000000000000 --- a/rules/sonic-pde-tests.mk +++ /dev/null @@ -1,17 +0,0 @@ -# sonic pdk package -# -# NOTE: sonic-config-engine is a build-time dependency of sonic-utilities -# due to unit tests which are run during the build. However, -# sonic-platform-common and swsssdk are runtime dependencies, and should be -# added here also. However, the current build system assumes all runtime -# dependencies are .deb packages. -# -# TODO: Create a way to specify both .deb and .whl runtime dependencies -# then add the aforementioned runtime dependencies here. -# - -SONIC_PLATFORM_PDE = sonic-platform-pde_1.0_amd64.deb -$(SONIC_PLATFORM_PDE)_SRC_PATH = $(SRC_PATH)/sonic-platform-pdk-pde -$(SONIC_PLATFORM_PDE)_DEPENDS += $(BRCM_SAI) $(BRCM_SAI_DEV) $(SWIG) - -SONIC_DPKG_DEBS += $(SONIC_PLATFORM_PDE) From f8ee054fd0fa401cd764c29905f64ed61a8ce4f3 Mon Sep 17 00:00:00 2001 From: William Schwartz Date: Wed, 9 Sep 2020 10:03:30 -0700 Subject: [PATCH 4/5] Support the new supervisord-dependent startup package in docker-pde --- dockers/docker-pde/supervisord.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dockers/docker-pde/supervisord.conf b/dockers/docker-pde/supervisord.conf index 58a32d833163..7a5d00cd25f7 100644 --- a/dockers/docker-pde/supervisord.conf +++ b/dockers/docker-pde/supervisord.conf @@ -4,9 +4,10 @@ logfile_backups=2 nodaemon=true [program:rsyslogd] -command=/bin/bash -c "rm -f /var/run/rsyslogd.pid && /usr/sbin/rsyslogd -n" +command=/usr/sbin/rsyslogd -n -iNONE" priority=1 autostart=true autorestart=false stdout_logfile=syslog stderr_logfile=syslog +dependent_startup=true From a622606e4adca779c1de87e6ec70954bce4dd1c4 Mon Sep 17 00:00:00 2001 From: William Schwartz Date: Thu, 24 Sep 2020 07:15:23 -0700 Subject: [PATCH 5/5] Updated rules/config to correct spelling error caught in review --- rules/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/config b/rules/config index 32b70b25c9e2..43eb06501e94 100644 --- a/rules/config +++ b/rules/config @@ -48,7 +48,7 @@ DEFAULT_PASSWORD = YourPaSsWoRd # If not set (default behavior) the default minigraph built into the image will be used. # ENABLE_DHCP_GRAPH_SERVICE = y -# ENABLE_PDE - Enable platform development enviroment +# ENABLE_PDE - Enable platform development environment # If set to y the PDE docker and associated tools and applications will be built as part of the # SONiC image and present on the system after installation. # ENABLE_PDE = y