SONiC是什么?
Software for Open Networking in the Cloud,根据Azure/SONiC Wiki:
★SONiC is an open source network operating system based on Linux that runs on switches from multiple vendors and ASICs.
”
SONiC是一个基于Linux开发的,可以运行在多个厂商交换机设备上的,通用的网络操作系统。所谓的“白盒”,就是厂商仅提供ASIC芯片和/或交换机硬件,用户在交换机上自己安装SONiC软件,而不再需要使用IOS-XE、XR、NX-OS等商业网络操作系统。
SONiC之所以能够成为一种大趋势,至关重要的一个原因是它采用了云原生架构,具备模块化、可观察、可部署、可测试、可替换、可处理的特征。

Container即进程
商业网络操作系统已经统治了行业几十年,不得不承认它们确实有些笨重了。虽然厂商也会宣称自己的NOS是模块化的,但每次升级都要升级整个NOS。如果遇到bug,能通过热补丁来修复的也比较少。
在操作系统内部,具体的功能都是由相应的进程来实现的。而Container就是进程。那么,将网络操作系统的进程都微服务化,以容器来做载体,就是很自然的事情了。
如果要升级,只需替换容器;想换一种控制面工具,例如把FRR换成GoBGP,也只需换个容器;如果要为交换机添加功能,新增一个容器即可...所有这些需求,都不需要通过升级网络操作系统来实现。另外,也有很多CI/CD工具,Automation工具,编排工具等存在于容器的生态系统。相比于传统NOS的开发模式,SONiC要敏捷很多。

在这些容器当中,Database Container无疑是最重要的一个。
Redis缓存数据库
交换机/路由器在运行过程中,需要存储/读取很多数据。例如MAC地址表,ARP表,路由表等等。这些数据都存储在内存中,设备重启数据就被清空。
这些需求,完全符合Redis数据库的特征。
Redis是REmote DIctionary Server的缩写。顾名思义,它其实就是个大字典,用来存储key/value键值对。同时,字典的键值又支持多种数据类型,非常适合用来存储网络设备的各种表项。例如:
{MAC Address: Interface}{IP Address: MAC Address}{Prefix: Next hop}
Redis的数据都存储在内存中,所以其性能可以满足高速网络设备的业务处理需求。Redis还可以为每个键设置生存时间,生存时间到期之后自动删除键,这也适合网络协议的各种计时器。
SONiC的各种容器通过TCP协议,向Redis-server容器更新并订阅自己感兴趣的数据,并根据数据的变化做出相应的Action。
可编程芯片和SAI
交换机作为一种工作在下三层的网络设备,其很多功能都依赖于ASIC的Pipeline。传统ASIC的Pipeline都是固定的,不能修改,将商用NOS换成SONiC的价值不大。但是可编程芯片和SONiC则是珠联璧合。
如果新增的网络功能需要修改ASIC的Driver和/或Pipeline才能实现,有2种方式来达成目的。一种是直接通过ASIC的SDK来修改;一种是通过调用SAI API来修改。

Switch Abstraction Interface就是一种API。SAI之于SDK,等同于Netconf/OpenConfig之于CLI。
各家芯片的SDK都不一样,但是SAI定义了一个标准的API,开发者不需要关心ASIC厂商的SDK是怎样定义的,通过标准的API就可以适配不同的ASIC。
怎样上手SONiC?
找台硬件交换机去安装SONiC显然不适合所有人,好在SONiC项目提供了Virtual Switch。目前有2个渠道下载SONiC Virtual Switch。
一个是Azure/SONiC官方的release,但是非常不推荐。首先,现在下载很麻烦。需要先访问:
https://github.com/Azure/sonic-buildimage
然后点击相应的release:

然后点击下面截图的1 published

然后点击最右侧3个点,下载全部的buildimage,接近8GB。下载之后解压缩,再把sonic-vs.img.gz
文件挑出来。

这还不是最坑的。最坑的是,Azure官方的Sonic-VS镜像有些问题,container很少,有些container无法running。
所以建议选择Broadcom提供的Sonic-VS image。目前是3.1.2版本。
如果你的模拟器是GNS3,可以看这个Blog:
https://www.linkedin.com/pulse/how-build-vsonic-lab-kamran-naqvi/
如果你和我一样使用EVE,请继续看下去。
Step 1
下载mssonic.yml
文件到templates
文件夹。注意,不要修改文件名!另外,如果你的EVE版本比较高,可能会看到子目录,例如/opt/unetlab/html/templates/intel
,或者/opt/unetlab/html/templates/amd
,取决于你的CPU架构。
root@bjlab-eve-ng:~# cd /opt/unetlab/html/templates/
root@bjlab-eve-ng:/opt/unetlab/html/templates# wget https://raw.githubusercontent.com/ercintorun/MsSonicEveNG/main/mssonic.yml
Step 2
在/opt/unetlab/addons/qemu/
目录新建一个以mssonic
开头的文件夹,然后下载image。
root@bjlab-eve-ng:/opt/unetlab/html/templates# cd /opt/unetlab/addons/qemu/
root@bjlab-eve-ng:/opt/unetlab/addons/qemu# mkdir mssonic-bcm-3.1.2
root@bjlab-eve-ng:/opt/unetlab/addons/qemu# cd mssonic-bcm-3.1.2/
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# wget https://github.com/Broadcom/sonic-VirtualSwitch/releases/download/3.1.2/sonic-vs-3.1.2.img.gz
Step 3
解压缩
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# ls
sonic-vs-3.1.2.img.gz
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# gunzip sonic-vs-3.1.2.img.gz
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# ls
sonic-vs-3.1.2.img
Step 4
重命名镜像文件为virtioa.qcow2
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# mv sonic-vs-3.1.2.img virtioa.qcow2
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# ls
virtioa.qcow2
Step 5
最后一步,修改权限。你有可能会看到下面的报错:
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# /opt/unetlab/wrappers/unl_wrapper -a fixpermissions
PHP Warning: scandir(/opt/unetlab/addons/iol/bin/): failed to open dir: No such file or directory in /opt/unetlab/html/includes/init.php on line 159
PHP Warning: scandir(): (errno 2): No such file or directory in /opt/unetlab/html/includes/init.php on line 159
PHP Warning: Invalid argument supplied for foreach() in /opt/unetlab/html/includes/init.php on line 169
打开/opt/unetlab/html/includes/init.php
文件查看,发现是第159行,在/opt/unetlab/addons/iol/
路径下找不到bin/
目录。进而导致第169行foreach()
运行失败。
$ioldir=scandir("/opt/unetlab/addons/iol/bin/");
修改之:
$ioldir=scandir("/opt/unetlab/addons/iol/");
顺便再给templates
增加一行mssonic
if (!isset($node_templates)) {
$node_templates = Array(
//...(snip)
'mssonic' => 'Azure SONiC',
再重新修改权限,Done!
root@bjlab-eve-ng:/opt/unetlab/addons/qemu/mssonic-bcm-3.1.2# /opt/unetlab/wrappers/unl_wrapper -a fixpermissions
SONiC Virtual Switch Get Started
可以在EVE里面添加SONiC节点了。

默认用户名/密码为admin
/YourPaSsWoRd
。
BCM的SONiC VS有一点不好,默认开启ZTP。在登陆之后,需要复制粘贴下面的命令,关闭ZTP。
sudo config ztp disable
y
另外要注意,这个VS镜像启动非常慢,大概需要3分钟左右。如果看不到CLI有输出,一定要保持耐心!
在看到下面的输出之后,说明系统启动成功,然后要保存刚才关闭ztp
的配置:
Verifying if all services have started
Services are started
Reload complete!
admin@sonic:~$ sudo config save -y
Running command: /usr/local/bin/sonic-cfggen -d --print-data > /run/tmpx8Va8K
Running command: mv -f /run/tmpx8Va8K /etc/sonic/config_db.json
Running command: sync;sync;sync
25740 Bytes written
我们可以看到SONiC运行了Docker Daemon Engine,并且有20个容器正在运行:
admin@sonic:~$ docker info
Client:
Debug Mode: false
Server:
Containers: 20
Running: 20
Paused: 0
Stopped: 0
Images: 20
Server Version: 19.03.0-rc3
Storage Driver: overlay2
...(Snip)
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
...(Snip)
Kernel Version: 4.9.0-11-2-amd64
Operating System: Debian GNU/Linux 9 (stretch)
...(Snip)
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
20个容器都没有向外发布端口:
admin@sonic:~$ docker container ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
af39746f15a2 docker-snmp-sv2:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes snmp
5d376f9c1e23 docker-nat:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes nat
28e2b5aecbf0 docker-lldp-sv2:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes lldp
9974af0d0d34 docker-l2mcd:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes l2mcd
52e55abedcd3 docker-sflow:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes sflow
74bf2f97ea88 docker-dhcp-relay:latest "/usr/bin/docker_ini…" 56 minutes ago Up 47 minutes dhcp_relay
17af023bcb29 docker-stp:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes stp
21973d589166 docker-sonic-mgmt-framework:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes mgmt-framework
681c537fb9f9 docker-udld:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes udld
ad9880041964 docker-tam:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes tam
30c35c009b97 docker-sonic-telemetry:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes telemetry
d111bfc17cb0 docker-router-advertiser:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes radv
e77eae01a3d1 docker-syncd-vs:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes syncd
5a668b291c4d docker-fpm-frr:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes bgp
32de08edb562 docker-teamd:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes teamd
4968776bf0dd docker-iccpd:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes iccpd
fa0fd78e3f8e docker-orchagent:latest "/usr/bin/supervisord" 56 minutes ago Up 48 minutes swss
fa5e6e97475f docker-platform-monitor:latest "/usr/bin/docker_ini…" 56 minutes ago Up 47 minutes pmon
5c882b8b0136 docker-vrrp:latest "/usr/bin/supervisord" 56 minutes ago Up 47 minutes vrrp
d0e87a1a91c3 docker-database:latest "/usr/local/bin/dock…" 2 months ago Up 50 minutes database
Docker的Network都是默认的:
admin@sonic:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
9034d41a3896 bridge bridge local
97abc007a292 host host local
5ce32d4ce005 none null local
来看看SONiC默认的接口和IP地址:
admin@sonic:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 50:07:00:02:00:00 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5207:ff:fe02:0/64 scope link flags 4000
valid_lft forever preferred_lft forever
...(Snip)
23: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:05:be:b0:7a brd ff:ff:ff:ff:ff:ff
inet 240.127.1.1/24 brd 240.127.1.255 scope global docker0
valid_lft forever preferred_lft forever
进去database
容器,再看看它的接口和IP地址:
admin@sonic:~$ docker container exec -it database sh
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 50:07:00:02:00:00 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5207:ff:fe02:0/64 scope link flags 4000
valid_lft forever preferred_lft forever
...(Snip)
23: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:05:be:b0:7a brd ff:ff:ff:ff:ff:ff
inet 240.127.1.1/24 brd 240.127.1.255 scope global docker0
valid_lft forever preferred_lft forever
和SONiC宿主机完全一样,说明这些容器的Network都是host
模式。那么lldp
和bgp
等容器向Redis-server读写数据的时候,实际上就是用本地的回环地址来通信。进一步确认一下:
# ps -ef | grep redis
root 29 1 0 15:40 pts/0 00:00:00 /usr/bin/redis-server 127.0.0.1:63970
root 31 1 3 15:40 pts/0 00:00:12 /usr/bin/redis-server 127.0.0.1:6379
root 33 1 0 15:40 pts/0 00:00:01 /usr/bin/redis-server 127.0.0.1:63793
root 34 1 0 15:40 pts/0 00:00:01 /usr/bin/redis-server 127.0.0.1:63792
root 81 67 0 15:47 pts/1 00:00:00 grep redis
这说明SONiC就是一个有很多接口的Linux,它上面运行的容器都处于同一个网络命名空间。当然,如果有特定的需求,用户也可以创建bridge
网络模式的容器。
SONiC可以在Linux模式下完成管理和配置工作,如果要查看命令行帮助,需要使用-?
代替网工习惯使用的?
admin@sonic:~$ show -?
Usage: show [OPTIONS] COMMAND [ARGS]...
SONiC command line - 'show' command
Options:
-?, -h, --help Show this message and exit.
Commands:
aaa Show AAA configuration
acl Show ACL related information
arp Show IP ARP table
...(Snip)
也可以进入交换机CLI,操作起来就和商用交换机完全相同了:
admin@sonic:~$ sonic-cli
sonic#
clear Clear commands
configure Enter configuration mode
copy Perform file copy operations
...(Snip)
sonic# config t
sonic(config)# ?
aaa AAA configuration
authentication Configure authentication modes
...(Snip)
如果要进一步学习,可以阅读SONiC Wiki
https://github.com/Azure/sonic-utilities/blob/master/doc/Command-Reference.md
还有这个Youtube频道:
https://www.youtube.com/love2network




