Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions images/dib/elements/hotstack-sonic-vs/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,43 @@ The config file contains shell-style variables for the host configuration:
- SWITCH_HOSTNAME: SONiC hostname (default: sonic)
- SONIC_IMAGE: Podman image tag (default: localhost/docker-sonic-vs:hotstack)

Host interfaces are moved directly into the container namespace:
- Host eth1 -> Container eth0 (SONiC Management0)
- Host eth2 -> Container eth1 (SONiC Ethernet0)
- Host eth3 -> Container eth2 (SONiC Ethernet1)
- etc.
Host interfaces are moved directly into the container namespace and mapped
to SONiC ports via lanemap.ini:
- Host eth1 -> Container eth1 -> SONiC Ethernet0
- Host eth2 -> Container eth2 -> SONiC Ethernet4
- Host eth3 -> Container eth3 -> SONiC Ethernet8
- etc. (continuing with +4 increment)

The config_db.json file contains SONiC native configuration in JSON format.

Interface Mapping
==================

**IMPORTANT**: The lanemap.ini file is REQUIRED and must be created via
cloud-init. The container will not start without it.

SONiC-VS uses a lanemap.ini file to map host eth interfaces to SONiC lane
numbers, which are then mapped to Ethernet ports. The file format is::

eth<N>:<lanes>

Example for a switch with 4 data interfaces::

eth1:25,26,27,28
eth2:29,30,31,32
eth3:33,34,35,36
eth4:37,38,39,40

The lane numbers must match those in /usr/share/sonic/hwsku/port_config.ini.
The standard mapping follows the containerlab pattern:
- eth1 maps to lanes 25-28, which map to Ethernet0
- eth2 maps to lanes 29-32, which map to Ethernet4
- eth3 maps to lanes 33-36, which map to Ethernet8
- etc.

Without this file, SONiC-VS creates virtual interfaces that are not connected
to the actual network, preventing OSPF/BGP neighbors from forming.

SSH Access
==========

Expand All @@ -61,6 +90,13 @@ cloud-init. The container will not start without it.
Example cloud-init configuration::

write_files:
- path: /etc/hotstack-sonic/lanemap.ini
content: |
eth1:25,26,27,28
eth2:29,30,31,32
eth3:33,34,35,36
owner: root:root
permissions: '0644'
- path: /etc/hotstack-sonic/authorized_keys
content: |
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... user@host
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ trap 'rm -rf "${BUILD_DIR}"' EXIT
# Get the directory where this script is located (extra-data.d)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Copy Containerfile, sshd.conf, and docker-wrapper.sh to build context
# Copy build files to build context
cp "${SCRIPT_DIR}/Containerfile" "${BUILD_DIR}/"
cp "${SCRIPT_DIR}/sshd.conf" "${BUILD_DIR}/"
cp "${SCRIPT_DIR}/bgpd.conf" "${BUILD_DIR}/"
cp "${SCRIPT_DIR}/ospfd.conf" "${BUILD_DIR}/"
cp "${SCRIPT_DIR}/start-sh.conf" "${BUILD_DIR}/"
cp "${SCRIPT_DIR}/docker-wrapper.sh" "${BUILD_DIR}/"

# Build custom image
Expand Down
13 changes: 9 additions & 4 deletions images/dib/elements/hotstack-sonic-vs/extra-data.d/Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
ARG BASE_IMAGE=localhost/docker-sonic-vs:latest
FROM ${BASE_IMAGE}

# Install sudo, create admin user, and configure SSH
# Install sudo, create admin user with explicit UID/GID, and configure SSH
# Using UID/GID 1000 for admin user to ensure consistency
RUN apt-get update && \
apt-get install -y sudo && \
rm -rf /var/lib/apt/lists/* && \
useradd -m -s /bin/bash -G sudo,redis,frrvty admin && \
groupadd -g 1000 admin && \
useradd -m -u 1000 -g 1000 -s /bin/bash -G sudo,redis,frrvty admin && \
echo "admin ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/admin && \
chmod 0440 /etc/sudoers.d/admin && \
mkdir -p /home/admin/.ssh && \
chown admin:admin /home/admin/.ssh && \
chown 1000:1000 /home/admin/.ssh && \
chmod 700 /home/admin/.ssh && \
ssh-keygen -A && \
mkdir -p /run/sshd
Expand All @@ -36,8 +38,11 @@ RUN apt-get update && \
COPY docker-wrapper.sh /usr/local/bin/docker
RUN chmod +x /usr/local/bin/docker

# Add supervisord configuration for sshd
# Add supervisord configuration for sshd, bgpd, ospfd, and start.sh override
COPY sshd.conf /etc/supervisor/conf.d/sshd.conf
COPY bgpd.conf /etc/supervisor/conf.d/bgpd.conf
COPY ospfd.conf /etc/supervisor/conf.d/ospfd.conf
COPY start-sh.conf /etc/supervisor/conf.d/start-sh.conf

# Metadata
LABEL maintainer="hotstack"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.

# Supervisord configuration for SSH daemon
[program:sshd]
command=/usr/sbin/sshd -D
priority=3
# Supervisord configuration for BGP daemon (FRR)
[program:bgpd]
command=/usr/lib/frr/bgpd -A 127.0.0.1 -f /etc/frr/frr.conf
priority=5
autostart=true
autorestart=true
stdout_logfile=syslog
Expand Down
23 changes: 23 additions & 0 deletions images/dib/elements/hotstack-sonic-vs/extra-data.d/ospfd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# 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.

# Supervisord configuration for OSPF daemon (FRR)
[program:ospfd]
command=/usr/lib/frr/ospfd -A 127.0.0.1 -f /etc/frr/frr.conf
priority=5
autostart=true
autorestart=true
stdout_logfile=syslog
stderr_logfile=syslog
21 changes: 21 additions & 0 deletions images/dib/elements/hotstack-sonic-vs/extra-data.d/start-sh.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

# Override start.sh to disable autostart
# We need to run start.sh manually after moving interfaces into the container
# because start.sh filters lanemap.ini based on available interfaces
[program:start.sh]
autostart=false
autorestart=false
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ frr.conf
FRRouting configuration file. This file is mounted into the SONiC
container at /etc/frr/frr.conf.

lanemap.ini (REQUIRED)
SONiC-VS interface mapping file. Maps host eth interfaces to SONiC
lane numbers, which are then mapped to Ethernet ports. This file is
mounted into the SONiC container at /usr/share/sonic/hwsku/lanemap.ini.
This file is REQUIRED - the container will not start without it.

Format: eth<N>:<lanes>
Example:
eth1:25,26,27,28
eth2:29,30,31,32
eth3:33,34,35,36

The lane numbers must match those defined in port_config.ini. The
standard mapping is:
eth1 -> lanes 25-28 -> Ethernet0
eth2 -> lanes 29-32 -> Ethernet4
eth3 -> lanes 33-36 -> Ethernet8
eth4 -> lanes 37-40 -> Ethernet12
etc. (continuing with +4 increment)

sonic_version.yml
SONiC version information file. Required by SONiC services. If not
provided, a default version file will be used.
Expand Down Expand Up @@ -51,14 +71,27 @@ Use write_files to create these configuration files:
}
}
}
- path: /etc/hotstack-sonic/lanemap.ini
content: |
# Maps eth1-8 to SONiC lanes
eth1:25,26,27,28
eth2:29,30,31,32
eth3:33,34,35,36
eth4:37,38,39,40
eth5:41,42,43,44
eth6:45,46,47,48
eth7:49,50,51,52
eth8:53,54,55,56
owner: root:root
permissions: '0644'
- path: /etc/hotstack-sonic/authorized_keys
content: |
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... user@host
owner: root:root
permissions: '0644'

Note: The authorized_keys file is REQUIRED. You can use Heat parameters
to inject SSH keys, for example:
Note: Both authorized_keys and lanemap.ini files are REQUIRED. You can
use Heat parameters to inject SSH keys, for example:

parameters:
controller_ssh_pub_key:
Expand All @@ -69,5 +102,9 @@ to inject SSH keys, for example:
properties:
user_data:
write_files:
- path: /etc/hotstack-sonic/lanemap.ini
content: |
eth1:25,26,27,28
eth2:29,30,31,32
- path: /etc/hotstack-sonic/authorized_keys
content: {get_param: controller_ssh_pub_key}
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,12 @@ def start_sonic_container(config: SonicConfig):
return False

LOG.info("Mounting SSH authorized_keys for admin user")
# Use idmap to remap host root (UID 0, GID 0) to container admin (UID 1000, GID 1000)
# This makes the file appear as owned by admin:admin inside the container
cmd.extend(
[
"-v",
f"{AUTHORIZED_KEYS_FILE}:/home/admin/.ssh/authorized_keys:ro",
f"{AUTHORIZED_KEYS_FILE}:/home/admin/.ssh/authorized_keys:ro,idmap=uids=0-1000-1;gids=0-1000-1",
]
)

Expand Down Expand Up @@ -413,6 +415,29 @@ def read_config_db():
return None


def trigger_sonic_initialization():
"""Manually trigger SONiC's start.sh script.

The start.sh script must run AFTER interfaces are moved into the container
because it filters lanemap.ini and port_config.ini based on available interfaces.
We disable autostart in supervisord and trigger it manually here.

:returns: True if start.sh completed successfully, False otherwise
"""
LOG.info("Triggering SONiC initialization (start.sh)...")
result = run_command(
["podman", "exec", "sonic", "supervisorctl", "start", "start.sh"], check=False
)
if result.returncode != 0:
LOG.error("Failed to start SONiC initialization script")
if result.stderr:
LOG.error(f"Error: {result.stderr}")
return False

LOG.info("SONiC initialization triggered successfully")
return True


def configure_management_interface(config_db):
"""Configure management interface from config_db.json.

Expand Down Expand Up @@ -554,36 +579,6 @@ def wait_for_sonic_services(timeout: int = 60) -> bool:
return False


def start_bgpd() -> bool:
"""Start BGP daemon for routing protocols.

bgpd is not started by default in SONiC-VS and must be started explicitly.
This follows the same approach as containerlab's sonic-vs implementation.
The daemon reads its configuration from /etc/frr/frr.conf which is mounted
at container startup.

zebra (the FRR routing manager) starts automatically with supervisord and
does not need to be started manually.

:returns: True if bgpd started successfully, False otherwise
"""
LOG.info("Starting BGP daemon...")

result = run_command(
["podman", "exec", "sonic", "supervisorctl", "start", "bgpd"],
check=False,
)

if result.returncode != 0:
LOG.error(f"Failed to start bgpd (exit code {result.returncode})")
if result.stderr:
LOG.error(f"Error: {result.stderr}")
return False

LOG.info("BGP daemon started successfully")
return True


def main():
"""Main entry point for SONiC switch host setup.

Expand Down Expand Up @@ -616,6 +611,12 @@ def main():
LOG.error("Failed to setup networking")
return 1

# Trigger SONiC initialization now that interfaces are in place
# The start.sh script filters lanemap.ini and port_config.ini based on available interfaces
if not trigger_sonic_initialization():
LOG.error("Failed to trigger SONiC initialization")
return 1

# Wait for critical SONiC services to be ready
if not wait_for_sonic_services(timeout=60):
LOG.error("Critical SONiC services (redis-server, orchagent) did not start")
Expand All @@ -633,11 +634,6 @@ def main():
LOG.error("Failed to configure management interface")
return 1

# Start BGP daemon (not started by default in SONiC-VS)
if not start_bgpd():
LOG.error("Failed to start BGP daemon")
return 1

LOG.info("SONiC switch host setup complete")
LOG.info("Container status:")
# Show container status (check=False so no exception raised)
Expand Down

This file was deleted.

Loading