Compile

编译环境

Since SONiC is based on debian, in order to ensure that we can successfully compile SONiC no matter what platform we are on, and that the compiled program can run on the corresponding platform, SONiC uses a containerized compilation environment -- it installs all the tools and dependencies in the corresponding This allows us to easily compile SONiC on any platform without worrying about dependency mismatches, such as packages that are higher in debian than in ubuntu, which may lead to some problems when the final program runs on This may lead to some unexpected errors when the final program is run on debian.

初始化编译环境

安装Docker

In order to support a containerized build environment, as a first step, we need to make sure that docker is installed on our machine.

Docker的安装方法可以参考官方文档,这里我们以Ubuntu为例,简单介绍一下安装方法。

First, we need to add the docker sources and certificates to the apt source list: the

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Then, we can quickly install it via apt:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

After installing docker's program, we also need to add our current account to docker's user group, then quit and log back in as the current user so we can run docker commands without sudo! This is very important because subsequent builds of SONiC do not allow sudo.

sudo gpasswd -a ${USER} docker

Once the installation is complete, don't forget to verify that it was successful by using the following command (note that sudo is not required here!):

docker run hello-world

安装其他依赖

sudo apt install -y python3-pip
pip3 install --user j2cli

拉取代码

3.1 代码仓库一章中,我们提到了SONiC的主仓库是sonic-buildimage。它也是我们目前为止唯一需要安装关注的repo。

Since this repository includes all other build-related repositories in the form of submodules, we need to be careful to add the -recuse-submodules option when pulling code via the git command:

git clone --recurse-submodules https://github.com/sonic-net/sonic-buildimage.git

If you forget to pull the submodule when pulling the code, you can fill it in with the following command:

git submodule update --init --recursive

Once the code has been downloaded, or for existing repo's, we can initialize the compilation environment with the following command. This command updates all current submodules to the required version to help us compile successfully:

sudo modprobe overlay
make init

了解并设置你的目标平台

SONiC虽然支持非常多种不同的交换机,但是由于不同型号的交换机使用的ASIC不同,所使用的驱动和SDK也会不同。SONiC通过SAI来封装这些变化,为上层提供统一的配置接口,但是在编译的时候,我们需要正确的设置好,这样才能保证我们编译出来的SONiC可以在我们的目标平台上运行。

Nowadays, SONiC mainly supports the following platforms:

  • barefoot
  • broadcom
  • marvell
  • mellanox
  • cavium
  • centec
  • nephos
  • innovium
  • vs

After confirming the platform, we can run the following command to configure our compilation environment:

make PLATFORM=<platform> configure
# e.g.: make PLATFORM=mellanox configure

Note

所有的make命令(除了make init)一开始都会检查并创建所有debian版本的docker builder:bullseye,stretch,jessie,buster。每个builder都需要几十分钟的时间才能创建完成,这对于我们平时开发而言实在完全没有必要,一般来说,我们只需要创建最新的版本即可(当前为bullseye,bookwarm暂时还没有支持),具体命令如下:

NOJESSIE=1 NOSTRETCH=1 NOBUSTER=1 make PLATFORM=<platform> configure

当然,为了以后开发更加方便,避免重复输入,我们可以将这个命令写入到~/.bashrc中,这样每次打开终端的时候,就会设置好这些环境变量了。

export NOJESSIE=1
export NOSTRETCH=1
export NOBUSTER=1

编译代码

编译全部代码

After setting up the platform, we can start compiling the code::

# The number of jobs can be the number of cores on your machine.
# Say, if you have 16 cores, then feel free to set it to 16 to speed up the build.
make SONIC_BUILD_JOBS=4 all

Note

当然,对于开发而言,我们可以把SONIC_BUILD_JOBS和上面其他变量一起也加入~/.bashrc中,减少我们的输入。

export SONIC_BUILD_JOBS=<number of cores>

编译子项目代码

As we can see from SONiC's Build Pipeline, compiling the entire project is very time consuming, and most of the time, our code changes will only affect a small part of the code, so is there any way to reduce our compilation effort? The answer is yes, we can specify make target to compile only the subprojects we need.

The files generated by each subproject in SONiC can be found in the target directory, e.g:

  • Docker containers: target/.gz,比如:target/docker-orchagent.gz
  • Deb packages: target/debs//.deb,比如:target/debs/bullseye/libswsscommon_1.0.0_amd64.deb
  • Python wheels: target/python-wheels//.whl,比如:target/python-wheels/bullseye/sonic_utilities-1.2-py3-none-any.whl

Once we have found the subproject we need, we can delete its generated files and then re-invoke the make command, here we use libswsscommon as an example, as follows:

# Remove the deb package for bullseye
rm target/debs/bullseye/libswsscommon_1.0.0_amd64.deb

# Build the deb package for bullseye
NOJESSIE=1 NOSTRETCH=1 NOBUSTER=1 make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb

检查和处理编译错误

If by chance an error occurs while compiling, we can check the exact cause by examining the log file of the failed project. In SONiC, each subcompiled project generates its associated log file, which we can easily find in the target directory, as follows:

$ ls -l
...
-rw-r--r--  1 r12f r12f 103M Jun  8 22:35 docker-database.gz
-rw-r--r--  1 r12f r12f  26K Jun  8 22:35 docker-database.gz.log      // Log file for docker-database.gz
-rw-r--r--  1 r12f r12f 106M Jun  8 22:44 docker-dhcp-relay.gz
-rw-r--r--  1 r12f r12f 106K Jun  8 22:44 docker-dhcp-relay.gz.log    // Log file for docker-dhcp-relay.gz

If we don't want to go to the root of the code and recompile it every time we update it and then check the log files, SONiC also provides a more convenient way to stop the build in the docker builder after it's done, so we can go directly to the corresponding directory and run the make command to recompile it:

# KEEP_SLAVE_ON=yes make <target>
KEEP_SLAVE_ON=yes make target/debs/bullseye/libswsscommon_1.0.0_amd64.deb
KEEP_SLAVE_ON=yes make all

Note

有些仓库中的部分代码在全量编译的时候是不会编译的,比如,sonic-swss-common中的gtest,所以使用这种方法重编译的时候,请一定注意查看原仓库的编译指南,以避免出错,如:https://github.com/sonic-net/sonic-swss-common#build-from-source

获取正确的镜像文件

Once compiled, we can find the image file we need in the target directory, but here's a question: which image do we use to install SONiC on our switch? Here it depends on what BootLoader or installer the switch is using, and the mapping is as follows:

Bootloader后缀
Aboot.swi
ONIE.bin
Grub.img.gz

部分升级

Obviously, when developing, it is quite inefficient to compile and install the image each time and then do a full install, so we can choose not to install the image and use the direct upgrade deb package to do a partial upgrade, thus improving our development efficiency.

We can upload the deb package to the /etc/sonic directory of the switch, the files in this directory will be mapped to the /etc/sonic directory of all containers, then we can enter the container and use the dpkg command to install the deb package as follows:

# Enter the docker container
docker exec -it <container> bash

# Install deb package
dpkg -i <deb-package>

参考资料

  1. SONiC Build Guide
  2. Install Docker Engine
  3. Github repo: sonic-buildimage
  4. SONiC Supported Devices and Platforms
  5. Wrapper for starting make inside sonic-slave container