Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support building multi-ASIC components #3269

Closed
Closed
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ dockers/docker-fpm-frr/Dockerfile
dockers/docker-fpm-gobgp/Dockerfile
dockers/docker-fpm-quagga/Dockerfile
dockers/docker-lldp-sv2/Dockerfile
dockers/docker-namespace/Dockerfile
dockers/docker-orchagent/Dockerfile
dockers/docker-platform-monitor/Dockerfile
dockers/docker-router-advertiser/Dockerfile
Expand Down
2 changes: 2 additions & 0 deletions dockers/docker-namespace/Dockerfile.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM debian:stretch
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this docker?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use the database as the namespace container, all other containers will use the same namespace as the database container. we do not need a separate namespace container.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this since I start the namespaces, then the topology service is started, then the other containers start. I wanted to have the topology set up before any SONiC containers were started.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

topology service is only required for kvm image. it is not necessary to have topology build before all containers start. We can build topology after database docker started. in fact, the bgp session will not be able to setup until host interfaces are created.

the only hard requirement I see is that the peer links has to be start before the syncd docker starts. since syncd will link the peer device with the host interface.


105 changes: 84 additions & 21 deletions files/build_templates/docker_image_ctl.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
#!/bin/bash

# single instance containers are still supported (even though it might not look like it)
# if no instance number is passed to this script, $DEV will simply be unset, resulting in docker
# commands being sent to the base container name. E.g. `docker start database$DEV` simply starts
# the container `database` if no instance number is passed since `$DEV` is not defined


{%- if docker_container_name == "namespace" %}
create_container() {
# Creates a basic container if it doesn't already exist

if ! `docker ps -a --format {{"'{{.Names}}'"}}| grep --quiet "{{docker_container_name}}$1"`; then
echo "No container for namespace $1 found, starting a new one"
docker run -id --name "{{docker_container_name}}$1" {{docker_image_name}}:latest bash
else
echo "Container for namespace $1 already exists"
docker start "{{docker_container_name}}$1"
fi
docker pause "{{docker_container_name}}$1" # pause to minimize resource consumption - we don't need the container, just it's network namespace
}


link_namespace() {
# Makes namespace of a docker container available in
# /var/run/netns so it can be managed with iproute2

mkdir -p /var/run/netns
PID="$(docker inspect -f {{"'{{.State.Pid}}'"}} "{{docker_container_name}}$1")"

if `ip netns | grep --quiet "{{docker_container_name}}$1"`; then # namespace exists
if [ $(readlink -f /var/run/netns/ns$1) = $(readlink -f /proc/$PID/ns/net) ]; then # namespace is correctly linked
return 0
else # if it's incorrectly linked remove it
ip netns delete "{{docker_container_name}}$1"
fi
fi

ln -s /proc/$PID/ns/net /var/run/netns/{{docker_container_name}}$1
}
{%- endif %}

function getMountPoint()
{
echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null
Expand All @@ -10,7 +50,7 @@ function updateHostName()
HOSTS=/etc/hosts
HOSTS_TMP=/etc/hosts.tmp

EXEC="docker exec -i {{docker_container_name}} bash -c"
EXEC="docker exec -i {{docker_container_name}}$DEV bash -c"

NEW_HOSTNAME="$1"
HOSTNAME=`$EXEC "hostname"`
Expand All @@ -25,7 +65,7 @@ function updateHostName()
# add entry with new hostname
$EXEC "echo -e \"127.0.0.1\t$NEW_HOSTNAME\" >> $HOSTS_TMP"

echo "Set hostname in {{docker_container_name}} container"
echo "Set hostname in {{docker_container_name}}$DEV container"
$EXEC "hostname '$NEW_HOSTNAME'"
$EXEC "cat $HOSTS_TMP > $HOSTS"
$EXEC "rm -f $HOSTS_TMP"
Expand Down Expand Up @@ -118,6 +158,11 @@ function postStartAction()
}

start() {

{%- if docker_container_name == "namespace" %}
create_container $DEV
link_namespace $DEV
{%- else %}
# Obtain boot type from kernel arguments
BOOT_TYPE=`getBootType`

Expand All @@ -136,7 +181,7 @@ start() {
HOSTNAME=`hostname`
fi

DOCKERCHECK=`docker inspect --type container {{docker_container_name}} 2>/dev/null`
DOCKERCHECK=`docker inspect --type container {{docker_container_name}}$DEV 2>/dev/null`
if [ "$?" -eq "0" ]; then
{%- if docker_container_name == "database" %}
DOCKERMOUNT=""
Expand All @@ -145,31 +190,39 @@ start() {
{%- endif %}
if [ x"$DOCKERMOUNT" == x"$HWSKU" ]; then
{%- if docker_container_name == "database" %}
echo "Starting existing {{docker_container_name}} container"
echo "Starting existing {{docker_container_name}}$DEV container"
{%- else %}
echo "Starting existing {{docker_container_name}} container with HWSKU $HWSKU"
echo "Starting existing {{docker_container_name}}$DEV container with HWSKU $HWSKU"
{%- endif %}
preStartAction
docker start {{docker_container_name}}
updateHostName "$HOSTNAME"
docker start {{docker_container_name}}$DEV
postStartAction
updateHostName "$HOSTNAME"
exit $?
fi

# docker created with a different HWSKU, remove and recreate
echo "Removing obsolete {{docker_container_name}} container with HWSKU $DOCKERMOUNT"
docker rm -f {{docker_container_name}}
echo "Removing obsolete {{docker_container_name}}$DEV container with HWSKU $DOCKERMOUNT"
docker rm -f {{docker_container_name}}$DEV
fi

{%- if docker_container_name == "database" %}
echo "Creating new {{docker_container_name}}$DEV container"
{%- else %}
echo "Creating new {{docker_container_name}}$DEV container with HWSKU $HWSKU"
{%- endif %}

if [ -z "$DEV" ]; then
NET="host"
else
NET="container:namespace$DEV"
fi

{%- if docker_container_name == "database" %}
echo "Creating new {{docker_container_name}} container"
{%- else %}
echo "Creating new {{docker_container_name}} container with HWSKU $HWSKU"
{%- endif %}
{%- if sonic_asic_platform == "mellanox" %}
# TODO: Mellanox will remove the --tmpfs exception after SDK socket path changed in new SDK version
{%- endif %}
docker create {{docker_image_run_opt}} \
--net=$NET \
{%- if install_debug_image == "y" %}
-v /src:/src:ro -v /debug:/debug:rw \
{%- endif %}
Expand Down Expand Up @@ -198,33 +251,43 @@ start() {
--tmpfs /tmp \
{%- endif %}
--tmpfs /var/tmp \
--hostname "$HOSTNAME" \
--name={{docker_container_name}} {{docker_image_name}}:latest || {
--name={{docker_container_name}}$DEV {{docker_image_name}}:latest || {
echo "Failed to docker run" >&1
exit 4
}

preStartAction
docker start {{docker_container_name}}
postStartAction
updateHostName "$HOSTNAME"
{%- endif %}
}

wait() {
docker wait {{docker_container_name}}
docker wait {{docker_container_name}}$DEV
}

stop() {
docker stop {{docker_container_name}}
docker stop {{docker_container_name}}$DEV
{%- if docker_container_name == "namespace" %}
ip netns delete "{{docker_container_name}}$DEV"
{%- endif %}
}

OP=$1
DEV=$2 # namespace/device number to operate on

case "$1" in
start|wait|stop|updateHostName)
start|wait|stop)
$1
;;
updateHostName)
cmd=$1
shift
shift 2
$cmd $@
;;
*)
echo "Usage: $0 {start|wait|stop|updateHostName new_hostname}"
echo "Usage: $0 {start namespace(optional)|wait namespace(optional)|stop namespace(optional)|updateHostName namespace(optional) new_hostname}"
exit 1
;;
esac
13 changes: 13 additions & 0 deletions files/build_templates/multi_instance/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Network namespace service
Requires=docker.service
After=docker.service

[Service]
User=root
ExecStartPre=/usr/bin/{{docker_container_name}}.sh start %i
ExecStart=/usr/bin/{{docker_container_name}}.sh wait %i
ExecStop=/usr/bin/{{docker_container_name}}.sh stop %i

[Install]
WantedBy=multi-user.target
14 changes: 14 additions & 0 deletions files/build_templates/sonic_debian_extension.j2
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ sudo cp $IMAGE_CONFIGS/hostname/hostname-config.service $FILESYSTEM_ROOT/etc/sy
echo "hostname-config.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo cp $IMAGE_CONFIGS/hostname/hostname-config.sh $FILESYSTEM_ROOT/usr/bin/

# Copy internal topology configuration scripts
{%- if sonic_asic_platform == "vs" %}
sudo cp $IMAGE_CONFIGS/topology/topology.service $FILESYSTEM_ROOT/etc/systemd/system/
echo "topology.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo cp $IMAGE_CONFIGS/topology/topology.sh $FILESYSTEM_ROOT/usr/bin
{%- endif %}

# Copy updategraph script and service file
j2 files/build_templates/updategraph.service.j2 | sudo tee $FILESYSTEM_ROOT/etc/systemd/system/updategraph.service
sudo cp $IMAGE_CONFIGS/updategraph/updategraph $FILESYSTEM_ROOT/usr/bin/
Expand Down Expand Up @@ -333,6 +340,13 @@ sudo cp {{script}} $FILESYSTEM_ROOT/usr/bin/
{% for service in installer_services.split(' ') -%}
if [ -f {{service}} ]; then
sudo cp {{service}} $FILESYSTEM_ROOT/etc/systemd/system/

{% if "@" in service and "namespace" not in service %}
MULTI_INSTANCE="{{service}}"
SINGLE_INSTANCE=${MULTI_INSTANCE/"@"}
sudo cp $SINGLE_INSTANCE $FILESYSTEM_ROOT/etc/systemd/system/
{% endif %}

echo "{{service}}" | sudo tee -a $GENERATED_SERVICE_FILE
fi
{% endfor %}
Expand Down
17 changes: 17 additions & 0 deletions files/image_config/topology/topology.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Unit]
Description=Internal topology service
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]

[Service]
Type=oneshot
User=root
RemainAfterExit=yes
ExecStart=/usr/bin/topology.sh start
ExecStop=/usr/bin/topology.sh stop

[Install]
WantedBy=multi-user.target

75 changes: 75 additions & 0 deletions files/image_config/topology/topology.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

start () {
# Move external links into assigned frontend namespaces
# eth0 - eth15: namespace2
# eth16 - eth31: namespace3
# eth32 - eth47: namespace4
# eth48 - eth63: namespace5
for NS in `seq 2 5`; do
theasianpianist marked this conversation as resolved.
Show resolved Hide resolved
for NUM in `seq 1 16`; do
ORIG="eth$((16 * $(($NS - 2)) + $NUM - 1))"
TEMP="ethTemp999"
NEW="eth$(($NUM + 16))"
ip link set dev $ORIG down
ip link set dev $ORIG name $TEMP # rename to prevent conflicts before renaming in new namespace
ip link set dev $TEMP netns namespace$NS
sudo ip netns exec namespace$NS ip link set $TEMP name $NEW # rename to final interface name
theasianpianist marked this conversation as resolved.
Show resolved Hide resolved
sudo ip netns exec namespace$NS ip link set $NEW up
done
done

# Connect all backend namespaces to frontend namespaces
for BACKEND in `seq 0 1`; do
for FRONTEND in `seq 2 5`; do
for LINK in `seq 1 8`; do
BACK_NAME="eth$((8 * $(($FRONTEND - 2)) + $LINK))"
FRONT_NAME="eth$((8 * $BACKEND + $LINK))"
TEMP_BACK="ethBack999"
TEMP_FRONT="ethFront999"

ip link add $TEMP_BACK type veth peer name $TEMP_FRONT # temporary name to prevent conflicts between interfaces
ip link set dev $TEMP_BACK netns namespace$BACKEND
ip link set dev $TEMP_FRONT netns namespace$FRONTEND

sudo ip netns exec namespace$BACKEND ip link set $TEMP_BACK name $BACK_NAME
sudo ip netns exec namespace$FRONTEND ip link set $TEMP_FRONT name $FRONT_NAME

sudo ip netns exec namespace$BACKEND ip link set $BACK_NAME up
sudo ip netns exec namespace$FRONTEND ip link set $FRONT_NAME up
done
done
done
}

stop() {
for NS in `seq 2 5`; do
for NUM in `seq 1 16`; do
TEMP="eth999"
OLD="eth$(($NUM + 16))"
NAME="eth$((16 * $(( $NS - 2)) + $NUM - 1))"
sudo ip netns exec namespace$NS ip link set dev $OLD down
sudo ip netns exec namespace$NS ip link set dev $OLD name $TEMP
sudo ip netns exec namespace$NS ip link set dev $TEMP netns 1
ip link set dev $TEMP name $NAME
ip link set dev $NAME up
done
done

for NS in `seq 0 1`; do
for NUM in `seq 1 32`; do
sudo ip netns exec namespace$NS ip link set dev eth$NUM down
sudo ip netns exec namespace$NS ip link delete dev eth$NUM
done
done
}

case "$1" in
start|stop)
$1
;;
*)
echo "Usage: $0 {start|stop}"
;;
esac

2 changes: 1 addition & 1 deletion platform/template/docker-syncd-base.mk
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ endif


$(DOCKER_SYNCD_BASE)_CONTAINER_NAME = syncd
$(DOCKER_SYNCD_BASE)_RUN_OPT += --net=host --privileged -t
$(DOCKER_SYNCD_BASE)_RUN_OPT += --privileged -t
$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro

35 changes: 23 additions & 12 deletions platform/vs/README.vsvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sudo apt-get install libvirt-clients qemu-kvm libvirt-bin
2. Create SONiC VM

```
$ virsh
$ sudo virsh
Welcome to virsh, the virtualization interactive terminal.

Type: 'help' for help with commands
Expand All @@ -22,14 +22,25 @@ Domain sonic created from sonic.xml
virsh #
```

2. Connect SONiC VM via console

```
$ telnet 127.0.0.1 7000
```

3. Connect SONiC VM via SSH

```
$ ssh -p 3040 [email protected]
```
3. Access virtual switch:

1. Connect SONiC VM via console
```
$ telnet 127.0.0.1 7000
```

OR

2. Connect SONiC VM via SSH

1. Connect via console (see 3.1 above)

2. Request a new DHCP address
```
sudo dhclient -v
```

3. Connect via SSH
```
$ ssh -p 3040 [email protected]
```
Loading